<?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: Casper Blockchain</title>
    <description>The latest articles on DEV Community by Casper Blockchain (@casperblockchain).</description>
    <link>https://dev.to/casperblockchain</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%2Forganization%2Fprofile_image%2F6205%2F4e4e73aa-6b9c-4c79-8657-b093c9296e8d.png</url>
      <title>DEV Community: Casper Blockchain</title>
      <link>https://dev.to/casperblockchain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/casperblockchain"/>
    <language>en</language>
    <item>
      <title>I Gave Claude the Ability to Trade on a DEX. Here's How It Works</title>
      <dc:creator>Michael Steuer</dc:creator>
      <pubDate>Tue, 24 Mar 2026 22:10:41 +0000</pubDate>
      <link>https://dev.to/casperblockchain/i-gave-claude-the-ability-to-trade-on-a-dex-heres-how-it-works-3m2j</link>
      <guid>https://dev.to/casperblockchain/i-gave-claude-the-ability-to-trade-on-a-dex-heres-how-it-works-3m2j</guid>
      <description>&lt;p&gt;Here's a simple question: &lt;em&gt;Can an AI agent trade on a DEX without ever touching a private key?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not read-only. Not "here's a price feed." Actually build a swap, sign it, submit it — end to end. And the answer, until now, was no.&lt;/p&gt;

&lt;p&gt;Every DeFi MCP server I looked at fell into one of two camps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read-only&lt;/strong&gt; — your agent can look at prices, maybe get a quote, but can't actually do anything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custodial&lt;/strong&gt; — hand over your keys and trust the server not to drain your wallet&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither is acceptable. Read-only is a toy. Custodial is a liability. So we built a third option.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hard Problem: It's Not the DEX. It's the Keys.
&lt;/h2&gt;

&lt;p&gt;The hard problem of agentic DeFi isn't connecting to a DEX. Any wrapper can do that. The hard problem is: &lt;strong&gt;who holds the keys?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CSPR.trade MCP does neither read-only nor custody. The agent builds the transaction remotely, your machine signs it locally, and &lt;strong&gt;keys never move&lt;/strong&gt;. That's not a feature. That's the architecture.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐      ┌───────────────────┐      ┌──────────────┐
│  AI Agent    │─────▶│  CSPR.trade MCP   │─────▶│  Casper DEX  │
│  (Claude,    │      │  Server           │      │  (on-chain)  │
│   Cursor,    │      │                   │      │              │
│   custom)    │◀─────│  Returns UNSIGNED │      │              │
└──────┬───────┘      │  transaction JSON │      └──────────────┘
       │              └───────────────────┘
       │
       ▼
┌───────────────┐
│  LOCAL SIGNER │  ← Keys live here. Nowhere else.
│  (your        │
│   machine)    │
└──────┬────────┘
       │
       ▼
  Submit signed tx → on-chain execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server never sees your private key. It can't. It builds an unsigned deploy, hands it back to the agent, and the agent signs locally before submitting. Zero custody. Zero trust assumptions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It: Two Servers, Zero Custody
&lt;/h2&gt;

&lt;p&gt;Add this to Claude Desktop, Cursor, or any MCP client:&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;"mcpServers"&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;"cspr-trade"&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.cspr.trade/mcp"&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;"cspr-signer"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"@make-software/cspr-trade-mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--signer"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"CSPR_TRADE_KEY_PATH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.casper/secret_key.pem"&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;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;p&gt;Two servers, one architecture: the &lt;strong&gt;remote server&lt;/strong&gt; handles market data and builds unsigned transactions. The &lt;strong&gt;local signer&lt;/strong&gt; signs them with your key. Keys never leave your machine — and the remote server doesn't even have the signing tools. It &lt;em&gt;can't&lt;/em&gt; touch your keys, by design.&lt;/p&gt;

&lt;p&gt;No API key. No auth. No accounts. Just add the config and your agent can trade on &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;CSPR.trade&lt;/a&gt;, the leading DEX on Casper Network.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Just want to explore?&lt;/strong&gt; The remote server works standalone — skip &lt;code&gt;cspr-signer&lt;/code&gt; and your agent gets full market data, quotes, and can build unsigned transactions. Add the signer when you're ready to execute.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Your Agent Can Actually Do
&lt;/h2&gt;

&lt;p&gt;14 tools, three categories:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See everything (no wallet needed):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_tokens&lt;/code&gt; — all tokens with live prices&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_pairs&lt;/code&gt; — trading pairs with liquidity depth&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_pair_details&lt;/code&gt; — deep stats on any pair&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_quote&lt;/code&gt; — "How much WETH do I get for 10,000 CSPR?"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_currencies&lt;/code&gt; — supported currencies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_swap_history&lt;/code&gt; — any account's trade history&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_liquidity_positions&lt;/code&gt; — LP positions and value&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_impermanent_loss&lt;/code&gt; — calculate IL for any position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Build transactions (returns unsigned JSON):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build_swap&lt;/code&gt; — construct a swap deploy&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build_approve_token&lt;/code&gt; — token approval for the router&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build_add_liquidity&lt;/code&gt; — add to a liquidity pool&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build_remove_liquidity&lt;/code&gt; — withdraw from a pool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sign locally:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sign_deploy&lt;/code&gt; — sign with a local key (signer mode only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Submit (back to remote server):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;submit_transaction&lt;/code&gt; — broadcast the signed deploy to the Casper network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight: your agent can freely explore market data and build transactions on the remote server. When it needs to sign, it crosses to the local signer — then the signed transaction goes &lt;em&gt;back&lt;/em&gt; to the remote server for submission. Keys never leave your machine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Walkthrough: Swapping 1000 CSPR for WETH
&lt;/h2&gt;

&lt;p&gt;Here's what actually happens when you tell Claude "Swap 1000 CSPR for WETH":&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Agent gets a quote&lt;/strong&gt; &lt;em&gt;(remote server)&lt;/em&gt;&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="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;get_quote(tokenIn:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CSPR"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tokenOut:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WETH"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;amountIn:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1000"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&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="err"&gt;amountOut:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.285"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;priceImpact:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.02%"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;route:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&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;p&gt;&lt;strong&gt;Step 2 — Agent builds the swap&lt;/strong&gt; &lt;em&gt;(remote server)&lt;/em&gt;&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="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;build_swap(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;publicKey:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"02036d..."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;tokenIn:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CSPR"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;tokenOut:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WETH"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;amountIn:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1000"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;slippage:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&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="err"&gt;deploy:&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="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;transaction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;JSON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;p&gt;&lt;strong&gt;Step 3 — Local signing&lt;/strong&gt; &lt;em&gt;(local signer — your machine)&lt;/em&gt;&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="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sign_deploy(deploy_json:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;key_source:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pem_file"&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&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="err"&gt;signedDeploy:&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="err"&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;p&gt;&lt;strong&gt;Step 4 — Submit&lt;/strong&gt; &lt;em&gt;(remote server)&lt;/em&gt;&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="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;submit_transaction(signed_deploy_json:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&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="err"&gt;deployHash:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a1b2c3..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;status:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"submitted"&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;p&gt;Notice the boundary: Steps 1-2 hit the remote server, Step 3 runs on the local signer, and Step 4 goes back to the remote server to submit. The signed transaction crosses back — but the private key never does. Your agent routes each tool call to the right server automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Self-Hosting and Testnet
&lt;/h2&gt;

&lt;p&gt;Want to run everything locally, or develop against testnet? Run the full server on your machine:&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;"mcpServers"&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;"cspr-trade"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"@make-software/cspr-trade-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"CSPR_TRADE_NETWORK"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CSPR_TRADE_KEY_PATH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.casper/secret_key.pem"&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;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;p&gt;In stdio mode, the full server includes all tools — market data, transaction building, signing, and submission — in a single process. Your keys stay local because the server &lt;em&gt;is&lt;/em&gt; local.&lt;/p&gt;

&lt;p&gt;The SDK is also available separately for custom integrations:&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; @make-software/cspr-trade-mcp-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why This Matters Beyond Casper
&lt;/h2&gt;

&lt;p&gt;Every blockchain is going to face this problem. As AI agents get more capable, they'll need to interact with DeFi — and the custody question doesn't go away just because the agent is smarter.&lt;/p&gt;

&lt;p&gt;The pattern we're using here — &lt;strong&gt;build remote, sign local&lt;/strong&gt; — isn't Casper-specific. It's a design pattern for any chain where you want agents to transact without surrendering keys. We just shipped it first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context: Casper v2.2.0
&lt;/h2&gt;

&lt;p&gt;This ships the same week Casper Network upgraded to v2.2.0 on mainnet. The v2.2.0 release marks a notable protocol upgrade, and CSPR.trade MCP is the first DeFi MCP server built for it. If you want to see what building on Casper looks like right now — this is it.&lt;/p&gt;




&lt;h2&gt;
  
  
  OpenClaw Skill
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://openclaw.ai" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt;? Install the skill from &lt;a href="https://clawhub.com" rel="noopener noreferrer"&gt;ClawHub&lt;/a&gt; and your agent gets the full workflow guide — intent classification, signing flows, safety checks — baked in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx clawhub@latest &lt;span class="nb"&gt;install &lt;/span&gt;cspr-trade-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skill teaches your agent &lt;em&gt;how&lt;/em&gt; to use the 14 tools: when to get a quote before building a swap, when to warn about price impact, how to handle local signing vs external wallets. It's the difference between "here are 14 tools, good luck" and "here's how a DeFi agent should behave."&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public endpoint:&lt;/strong&gt; &lt;a href="https://mcp.cspr.trade/mcp" rel="noopener noreferrer"&gt;mcp.cspr.trade/mcp&lt;/a&gt; — add it and go&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/make-software/cspr-trade-mcp" rel="noopener noreferrer"&gt;make-software/cspr-trade-mcp&lt;/a&gt; — MIT, PRs welcome&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@make-software/cspr-trade-mcp" rel="noopener noreferrer"&gt;@make-software/cspr-trade-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ClawHub skill:&lt;/strong&gt; &lt;a href="https://clawhub.com/skills/cspr-trade-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;cspr-trade-mcp&lt;/code&gt;&lt;/a&gt; — install with &lt;code&gt;npx clawhub install cspr-trade-mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent SKILL.md:&lt;/strong&gt; &lt;a href="https://mcp.cspr.trade/SKILL.md" rel="noopener noreferrer"&gt;mcp.cspr.trade/SKILL.md&lt;/a&gt; — structured instructions for AI agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSPR.trade:&lt;/strong&gt; &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;cspr.trade&lt;/a&gt; — the DEX itself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions? Drop a comment or &lt;a href="https://github.com/make-software/cspr-trade-mcp/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;— Built by &lt;a href="https://make.services" rel="noopener noreferrer"&gt;MAKE&lt;/a&gt;, the team behind Casper's core developer tools.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Opening the Playbook: Why We're Open-Sourcing Casper's Core DeFi Infrastructure</title>
      <dc:creator>Michael Steuer</dc:creator>
      <pubDate>Thu, 19 Mar 2026 18:30:15 +0000</pubDate>
      <link>https://dev.to/casperblockchain/opening-the-playbook-why-were-open-sourcing-caspers-core-defi-infrastructure-3d9o</link>
      <guid>https://dev.to/casperblockchain/opening-the-playbook-why-were-open-sourcing-caspers-core-defi-infrastructure-3d9o</guid>
      <description>&lt;p&gt;&lt;em&gt;Four production systems, security-audited by Halborn, open-sourced in one week. A naming service, a decentralized exchange, liquid staking, and EIP-712 typed signatures. All live on mainnet. All yours now.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Earlier this week, I &lt;a href="https://github.com/casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;open-sourced casper-eip-712&lt;/a&gt;, a Rust crate that brings Ethereum's typed signing standard to Casper. I wrote about why we did it, what it unlocks, and how it started with a security auditor telling us we had a gap.&lt;/p&gt;

&lt;p&gt;That was &lt;a href="https://dev.to/casperblockchain/why-we-brought-ethereums-most-important-signing-standard-to-casper-38k2"&gt;yesterday&lt;/a&gt;. We weren't done.&lt;/p&gt;

&lt;p&gt;Today I'm announcing that we've open-sourced three additional contract repositories that power core DeFi infrastructure on Casper Network:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/make-software/cspr-name-contracts" rel="noopener noreferrer"&gt;cspr-name-contracts&lt;/a&gt;&lt;/strong&gt;: the smart contracts behind &lt;a href="https://cspr.name" rel="noopener noreferrer"&gt;CSPR.name&lt;/a&gt;, Casper's decentralized naming service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/odradev/casper-trade" rel="noopener noreferrer"&gt;casper-trade&lt;/a&gt;&lt;/strong&gt;: the DEX contracts powering &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;CSPR.trade&lt;/a&gt;, a Uniswap V2-style automated market maker&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/casper-ecosystem/liquid-staking-contracts" rel="noopener noreferrer"&gt;liquid-staking-contracts&lt;/a&gt;&lt;/strong&gt;: the liquid staking protocol behind &lt;a href="https://casper.wiselending.com" rel="noopener noreferrer"&gt;casper.wiselending.com&lt;/a&gt;, enabling staked CSPR to remain liquid as sCSPR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't proofs of concept. They're not hackathon projects gathering dust. Each of these repositories powers a live product with real users on Casper mainnet right now. And critically, each has been independently security-audited by &lt;a href="https://halborn.com" rel="noopener noreferrer"&gt;Halborn&lt;/a&gt;, one of the leading blockchain security firms in the industry:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/make-csprname-7b1108" rel="noopener noreferrer"&gt;CSPR.name audit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/odradevcasper--trade-af1b5a" rel="noopener noreferrer"&gt;CSPR.trade audit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/odra---liquid-staking-231379" rel="noopener noreferrer"&gt;Liquid staking audit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Production-deployed, battle-tested, and security-audited. That's the bar we're setting for what "open source" means on Casper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Open-Source, Why Now
&lt;/h2&gt;

&lt;p&gt;Let me be direct about the motivation. Casper Network is an open-source Layer 1 blockchain with decentralized community governance. The protocol is open. The node software is open. The SDK is open. But until now, the production-grade application contracts, the ones that actually demonstrate how to build real things on Casper, weren't.&lt;/p&gt;

&lt;p&gt;That's a gap. And it's the kind of gap that makes life harder for builders.&lt;/p&gt;

&lt;p&gt;If you wanted to build a naming service on Casper, you'd start from scratch. If you wanted to build a DEX, you'd reverse-engineer how AMMs work on EVM chains and figure out how to translate that to Casper's architecture. If you wanted to implement liquid staking, you'd be pioneering patterns that someone had already solved, just behind closed doors.&lt;/p&gt;

&lt;p&gt;We're opening those doors.&lt;/p&gt;

&lt;p&gt;The timing matters, too. Casper's v2.2.0 mainnet upgrade launches on March 23rd. Validators are already staging, with 83% of stake staged and climbing. The protocol is evolving. Upgradeable smart contracts, improved developer ergonomics, a maturing DeFi stack. But none of that matters if builders don't have the reference material, the production-tested patterns, and the working code to build on.&lt;/p&gt;

&lt;p&gt;Open-sourcing these repositories isn't an act of charity. It's infrastructure investment. It's saying: "Here's how we solved naming, liquidity, staking, and typed signatures on Casper. Take it. Learn from it. Build on it. Make it better."&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Teams, One Commons
&lt;/h2&gt;

&lt;p&gt;One thing worth highlighting: these four repositories come from three different organizations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/make-software" rel="noopener noreferrer"&gt;make-software&lt;/a&gt;&lt;/strong&gt; (MAKE) hosts the CSPR.name contracts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/odradev" rel="noopener noreferrer"&gt;odradev&lt;/a&gt;&lt;/strong&gt; (Odra) built the CSPR.trade DEX&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/casper-ecosystem" rel="noopener noreferrer"&gt;casper-ecosystem&lt;/a&gt;&lt;/strong&gt; hosts the liquid staking contracts and casper-eip-712&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how we operate. The Casper Association doesn't build everything in-house. It functions as an ecosystem orchestrator, ensuring that different teams across the ecosystem contribute to, collaborate on, and benefit from shared infrastructure. MAKE, Odra, WiseLending: each team brings deep expertise in their domain. The Association's job is to make sure that expertise compounds instead of staying siloed.&lt;/p&gt;

&lt;p&gt;Open-sourcing these repositories is a concrete expression of that philosophy. Three teams, four repos, one ecosystem commons.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Framework That Runs the Stack
&lt;/h2&gt;

&lt;p&gt;Three of the four repositories are built entirely with &lt;a href="https://odra.dev" rel="noopener noreferrer"&gt;Odra&lt;/a&gt;, the Rust-native smart contract framework for Casper. The fourth, casper-eip-712, is a vanilla Rust crate by design (it needs to work in any environment, including &lt;code&gt;no_std&lt;/code&gt;). But we built its &lt;a href="https://github.com/casper-ecosystem/casper-eip-712/tree/master/examples/permit-token" rel="noopener noreferrer"&gt;demo project&lt;/a&gt;, a full CEP-18 token with gasless permit/approve, in Odra specifically to demonstrate how the vanilla crate integrates with the framework.&lt;/p&gt;

&lt;p&gt;If you're not familiar with Odra: think of it as what OpenZeppelin provides for the EVM ecosystem, but more comprehensive and designed from the ground up for Casper's architecture. Odra handles the contract lifecycle, testing infrastructure, deployment tooling, and factory patterns, so you can focus on your application logic rather than blockchain plumbing.&lt;/p&gt;

&lt;p&gt;The fact that three production DeFi systems were built with Odra, and the fourth integrates seamlessly, is itself a strong signal. A naming protocol, a full Uniswap V2 port, and a liquid staking system with protocol-level integration, all built, tested, audited, deployed, and running in production using the same framework.&lt;/p&gt;

&lt;p&gt;For developers considering Casper, these repos serve as a real-world Odra curriculum:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cspr-name-contracts&lt;/strong&gt; demonstrates domain registration, resolution, and the tradable NFT-like ownership model&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;casper-trade&lt;/strong&gt; shows how to port a battle-tested EVM design (Uniswap V2) to Casper, including Odra's factory pattern for runtime contract deployment, which is a genuinely different approach from EVM's &lt;code&gt;create2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;liquid-staking-contracts&lt;/strong&gt; illustrates protocol-level integration, the sCSPR liquid token pattern, and Gherkin-style BDD tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;casper-eip-712&lt;/strong&gt; demonstrates how standalone Rust crates integrate with Odra contracts in production&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Under the Hood
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CSPR.name: Decentralized Naming for Casper
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/make-software/cspr-name-contracts" rel="noopener noreferrer"&gt;make-software/cspr-name-contracts&lt;/a&gt; | &lt;a href="https://www.halborn.com/audits/casper-association/make-csprname-7b1108" rel="noopener noreferrer"&gt;Halborn audit&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Live product:&lt;/strong&gt; &lt;a href="https://cspr.name" rel="noopener noreferrer"&gt;CSPR.name&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;14c8b2f09ad2ef34c23bff91d52e6f48cbd714ea1fa8b3e71d26547ebfd1229c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's a Casper account hash. Try sending tokens to it from memory. Now try sending tokens to &lt;code&gt;michael.cspr&lt;/code&gt;. That's the problem CSPR.name solves.&lt;/p&gt;

&lt;p&gt;CSPR.name is Casper's official naming service. It replaces cryptographic account hashes with human-readable &lt;code&gt;.cspr&lt;/code&gt; names, making the entire ecosystem more navigable. Register a name, and it becomes your on-chain identity, recognized across &lt;a href="https://cspr.live" rel="noopener noreferrer"&gt;CSPR.live&lt;/a&gt;, Casper Wallet, dApps, and the broader ecosystem.&lt;/p&gt;

&lt;p&gt;But CSPR.name goes beyond simple name-to-address resolution. As of the latest release, names are &lt;a href="https://www.casper.network/news/cspr-names-are-now-tradable-on-cspr-market" rel="noopener noreferrer"&gt;fully tradable on CSPR.market&lt;/a&gt;. You can buy, sell, and make purchase offers for names. Your .cspr name isn't just a convenience. It's a digital asset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What developers can learn from this repo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name registration and resolution contract architecture using Odra&lt;/li&gt;
&lt;li&gt;Tradable naming rights: turning registered names into transferable assets&lt;/li&gt;
&lt;li&gt;Integration with marketplace contracts&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;cargo odra build&lt;/code&gt; and &lt;code&gt;cargo odra test&lt;/code&gt; for the full development lifecycle
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone and run tests locally&lt;/span&gt;
git clone https://github.com/make-software/cspr-name-contracts
&lt;span class="nb"&gt;cd &lt;/span&gt;cspr-name-contracts
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
cargo odra &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSPR.trade: Native Decentralized Exchange
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/odradev/casper-trade" rel="noopener noreferrer"&gt;odradev/casper-trade&lt;/a&gt; | &lt;a href="https://www.halborn.com/audits/casper-association/odradevcasper--trade-af1b5a" rel="noopener noreferrer"&gt;Halborn audit&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Live product:&lt;/strong&gt; &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;CSPR.trade&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CSPR.trade is Casper's native DEX, a Uniswap V2-style automated market maker built specifically for Casper's architecture. It provides token swaps, liquidity pools, and yield farming. With deterministic finality and non-custodial execution, every swap, pool rebalance, and fee distribution is verifiable on-chain.&lt;/p&gt;

&lt;p&gt;What makes this repo particularly interesting for developers is how faithfully it ports the Uniswap V2 architecture while handling the fundamental differences between EVM and Casper:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The factory pattern:&lt;/strong&gt; On Ethereum, Uniswap's factory deploys Pair contracts using &lt;code&gt;create2&lt;/code&gt; with the Pair bytecode stored in the Factory. Casper doesn't have &lt;code&gt;create2&lt;/code&gt;. Instead, Odra provides a &lt;code&gt;factory=on&lt;/code&gt; directive that auto-generates a PairFactory contract. The PairFactory's sole purpose is managing deployments and upgrades of Pair contracts. Factory calls &lt;code&gt;factory()&lt;/code&gt; on PairFactory, which deploys a new Pair and returns its address.&lt;/p&gt;

&lt;p&gt;This is one of those architectural differences that would take a team weeks to figure out from scratch. Now it's documented, tested, audited, and open.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test parity:&lt;/strong&gt; The tests are based directly on the original Uniswap V2 test suites (&lt;code&gt;UniswapV2Router01.spec.ts&lt;/code&gt;, &lt;code&gt;UniswapV2Router02.spec.ts&lt;/code&gt;, &lt;code&gt;UniswapV2Factory.spec.ts&lt;/code&gt;, and &lt;code&gt;UniswapV2Pair.spec.ts&lt;/code&gt;). This isn't a loose reimplementation; it's a faithful port with behavioral verification against the original.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contract architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Pair&lt;/code&gt;: The AMM pair contract (deployed by PairFactory, not directly). Corresponds to UniswapV2Pair.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PairFactory&lt;/code&gt;: Auto-generated by Odra. Responsible for deploying and upgrading Pair contracts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Router&lt;/code&gt;: Corresponds to UniswapV2Router. Entry point for swaps and liquidity operations.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Factory&lt;/code&gt;: Pair management. Corresponds to UniswapV2Factory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WrappedNativeToken&lt;/code&gt;: From Odra modules, wraps native CSPR for use in AMM pools.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone, install, and test&lt;/span&gt;
git clone https://github.com/odradev/casper-trade
&lt;span class="nb"&gt;cd &lt;/span&gt;casper-trade
cargo &lt;span class="nb"&gt;install &lt;/span&gt;cargo-odra
just &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Liquid Staking: The StakedCSPR Protocol
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/casper-ecosystem/liquid-staking-contracts" rel="noopener noreferrer"&gt;casper-ecosystem/liquid-staking-contracts&lt;/a&gt; | &lt;a href="https://www.halborn.com/audits/casper-association/odra---liquid-staking-231379" rel="noopener noreferrer"&gt;Halborn audit&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Live product:&lt;/strong&gt; &lt;a href="https://casper.wiselending.com" rel="noopener noreferrer"&gt;casper.wiselending.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the staking dilemma every Proof-of-Stake network faces: users who stake their tokens to secure the network get their capital locked up. They earn rewards, but they lose liquidity. They can't use those tokens in DeFi. They can't respond to market conditions without waiting through unbonding periods. So they face a choice: security or liquidity.&lt;/p&gt;

&lt;p&gt;Liquid staking removes that choice.&lt;/p&gt;

&lt;p&gt;When you stake CSPR through the liquid staking protocol, you receive sCSPR, a liquid token that represents your staked position. Your original CSPR stays staked and continues earning network rewards. Meanwhile, sCSPR is freely transferable. You can use it in &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;CSPR.trade&lt;/a&gt; pools. You can use it as collateral. Your capital works in two places at once.&lt;/p&gt;

&lt;p&gt;On Casper, this &lt;a href="https://www.casper.network/news/liquid-staking" rel="noopener noreferrer"&gt;isn't a third-party bolt-on&lt;/a&gt;. It's built with protocol-level awareness, in collaboration with &lt;a href="https://wiselending.com" rel="noopener noreferrer"&gt;WiseLending&lt;/a&gt;. No custodians, no synthetic wrappers, no workarounds that bypass the base layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes this repo especially valuable for developers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The StakedCSPR token contract implementation, a real-world example of a liquid representation token&lt;/li&gt;
&lt;li&gt;Gherkin-style BDD test specifications in the &lt;code&gt;tests/features&lt;/code&gt; folder, showing how to write readable, verifiable test suites for complex DeFi logic&lt;/li&gt;
&lt;li&gt;Full CLI tooling for deployment and interaction&lt;/li&gt;
&lt;li&gt;Protocol-level staking integration patterns
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone and test&lt;/span&gt;
git clone https://github.com/casper-ecosystem/liquid-staking-contracts
&lt;span class="nb"&gt;cd &lt;/span&gt;liquid-staking-contracts
just &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="c"&gt;# Deploy to testnet (configure .env first)&lt;/span&gt;
just build-contracts
just cli deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Let me be concrete about what you can do with these repositories today:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to build a naming service on another domain&lt;/strong&gt;, fork cspr-name-contracts. The architecture handles registration, resolution, renewal, and marketplace integration. Adapt the domain logic to your use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to build a DEX or AMM on Casper&lt;/strong&gt;, casper-trade gives you a production-tested, Halborn-audited Uniswap V2 implementation. Add new pool types, modify fee structures, build a frontend. The hard contract work is done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to incorporate liquid staking functionality in your dApp&lt;/strong&gt;, liquid-staking-contracts shows you the pattern. Whether you're building a lending protocol, a yield optimizer, or anything that benefits from compounding staking rewards alongside your application's native functionality, the sCSPR token design, the staking/unstaking flow, and the reward distribution logic are all there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you need typed signatures for any cross-chain, gasless, or multi-party signing use case&lt;/strong&gt;, casper-eip-712 handles encoding, hashing, domain separation, and verification. Drop it in as a crate dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you're learning Odra&lt;/strong&gt;, these repos are your graduate-level coursework. Registration systems, AMMs, staking protocols, cryptographic primitives. Each demonstrates different Odra patterns in production context, with Halborn audits that serve as implicit code quality benchmarks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Broader Picture
&lt;/h2&gt;

&lt;p&gt;When I wrote about &lt;a href="https://medium.com/@mssteuer/turns-out-we-werent-exaggerating-who-could-ve-predicated-that-ffa4b794ab65" rel="noopener noreferrer"&gt;building CSPR.guru&lt;/a&gt; a few months ago, I made the case that Casper's developer experience, powered by Odra, CSPR.click, CSPR.cloud, and the rest of MAKE's toolchain, is genuinely best-in-class. I built a full prediction market, solo, in my spare evenings, using only Casper ecosystem tools.&lt;/p&gt;

&lt;p&gt;But I also know that "best-in-class tools" means nothing if builders can't see what production-grade code looks like on your platform. Documentation gets you started. Tutorials teach you patterns. But nothing replaces reading real code that runs in production, serving real users, handling real money, and surviving a Halborn audit.&lt;/p&gt;

&lt;p&gt;That's what these repositories provide. Not examples. Not templates. Production systems with the security receipts to prove it.&lt;/p&gt;

&lt;p&gt;Four repos. Three teams. Three Halborn audits. One ecosystem.&lt;/p&gt;

&lt;p&gt;As we approach the v2.2.0 mainnet upgrade on March 23rd, with 83% of stake already staged, we're not just upgrading the protocol. We're opening the entire application layer. The code that powers Casper's DeFi infrastructure is now the same code you can fork, study, extend, and deploy.&lt;/p&gt;

&lt;p&gt;Build something.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Repositories:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;casper-eip-712&lt;/a&gt;: EIP-712 typed signatures for Casper&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/make-software/cspr-name-contracts" rel="noopener noreferrer"&gt;cspr-name-contracts&lt;/a&gt;: CSPR.name decentralized naming protocol&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/odradev/casper-trade" rel="noopener noreferrer"&gt;casper-trade&lt;/a&gt;: Uniswap V2-style DEX for Casper&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/casper-ecosystem/liquid-staking-contracts" rel="noopener noreferrer"&gt;liquid-staking-contracts&lt;/a&gt;: Liquid staking with StakedCSPR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security audits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/make-csprname-7b1108" rel="noopener noreferrer"&gt;CSPR.name (Halborn)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/odradevcasper--trade-af1b5a" rel="noopener noreferrer"&gt;CSPR.trade (Halborn)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.halborn.com/audits/casper-association/odra---liquid-staking-231379" rel="noopener noreferrer"&gt;Liquid staking (Halborn)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Live products:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cspr.name" rel="noopener noreferrer"&gt;CSPR.name&lt;/a&gt; | &lt;a href="https://cspr.trade" rel="noopener noreferrer"&gt;CSPR.trade&lt;/a&gt; | &lt;a href="https://casper.wiselending.com" rel="noopener noreferrer"&gt;Liquid Staking&lt;/a&gt; | &lt;a href="https://csprbridge.com" rel="noopener noreferrer"&gt;CSPRbridge&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learn more:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://odra.dev/docs" rel="noopener noreferrer"&gt;Odra Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.casper.network" rel="noopener noreferrer"&gt;Casper Developer Portal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>opensource</category>
      <category>web3</category>
    </item>
    <item>
      <title>Why We Brought Ethereum's Most Important Signing Standard to Casper</title>
      <dc:creator>Michael Steuer</dc:creator>
      <pubDate>Tue, 17 Mar 2026 19:20:41 +0000</pubDate>
      <link>https://dev.to/casperblockchain/why-we-brought-ethereums-most-important-signing-standard-to-casper-38k2</link>
      <guid>https://dev.to/casperblockchain/why-we-brought-ethereums-most-important-signing-standard-to-casper-38k2</guid>
      <description>&lt;p&gt;Every blockchain that wants to play in the big leagues (cross-chain bridges, gasless transactions, AI agents moving money on your behalf) needs EIP-712. It's the standard that makes typed, domain-separated signatures possible. Ethereum figured this out years ago. Uniswap uses it. Aave uses it. OpenSea uses it. It's the plumbing behind every "approve without paying gas" interaction you've ever done on an EVM chain.&lt;/p&gt;

&lt;p&gt;Casper has it now.&lt;/p&gt;

&lt;p&gt;This isn't something we planned on a roadmap six months ago. It started the way the best infrastructure usually starts: with a security auditor telling us we had a gap. During the Halborn security audit of &lt;a href="https://csprbridge.com" rel="noopener noreferrer"&gt;CSPRbridge.com&lt;/a&gt;, our cross-chain bridge connecting Casper to EVM networks, the auditors flagged that our attestation verification was using ad-hoc signature encoding. Custom &lt;code&gt;encodePacked&lt;/code&gt;-style hashing, hand-rolled for each message type. It worked, but it was brittle, non-standard, and the kind of thing that keeps security engineers up at night.&lt;/p&gt;

&lt;p&gt;We could have patched the finding and moved on. That's what most teams do: fix the specific issue, close the ticket, ship the update. Instead, we asked ourselves: "If this is a gap in the bridge, isn't it a gap in the entire ecosystem?" The answer was yes. So we built infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Roll-Your-Own Signatures Fail
&lt;/h2&gt;

&lt;p&gt;Here's a scenario that plays out more often than anyone in crypto likes to admit. A team builds a bridge, or a cross-chain messaging protocol, or a multi-chain dApp. They need signatures: attestations that something happened on Chain A, verified on Chain B. So they roll their own encoding. They pick a hash function, concatenate some fields, maybe add a prefix. Ship it.&lt;/p&gt;

&lt;p&gt;Then someone replays a signature from testnet on mainnet. Or submits an attestation meant for the ERC-20 locker contract against the NFT bridge. Or finds that the "domain" is just the contract name hard-coded as a string, with nothing tying the signature to a specific deployment.&lt;/p&gt;

&lt;p&gt;This is what domain separation solves, and it's what the ad-hoc approach almost always gets wrong. When every project invents its own encoding, you get inconsistency, incompatibility between systems, and attack surfaces that are invisible until someone exploits them.&lt;/p&gt;

&lt;p&gt;Security auditors don't tell you what's nice to have. They tell you what will get you exploited.&lt;/p&gt;

&lt;p&gt;That Halborn audit was the catalyst. The bridge's attestation verification was using raw &lt;code&gt;keccak256&lt;/code&gt; with &lt;code&gt;encodePacked&lt;/code&gt;-style concatenation: four different hash functions, each assembling bytes manually for different message types. Functional? Yes. Standardized? No. Upgradeable without breaking every deployed relayer? Absolutely not.&lt;/p&gt;

&lt;p&gt;We decided that if we were going to fix the bridge, we'd fix it for the whole ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What EIP-712 Is and Why Ethereum Got It Right
&lt;/h2&gt;

&lt;p&gt;If you've been building on Ethereum, you've already used EIP-712, even if you didn't know it by name. Every time you've signed a "permit" in MetaMask and seen a nicely formatted breakdown of what you're approving (the token, the spender, the amount), that's EIP-712 at work.&lt;/p&gt;

&lt;p&gt;Before EIP-712, signing on Ethereum meant signing opaque byte blobs. Your wallet would show you a hex string and essentially ask: "Do you trust this?" The answer should always have been "no," but people clicked "sign" anyway. EIP-712 changed this by introducing typed structured data hashing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human-readable in wallets.&lt;/strong&gt; Instead of a hex blob, users see the actual fields they're signing: token name, amount, recipient, deadline. The wallet can display this because the data has a schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain-separated.&lt;/strong&gt; Every signature is bound to a specific domain: a contract address, a chain ID, a protocol version. A signature for Uniswap on Ethereum mainnet cannot be replayed against a copycat contract on Arbitrum. The domain is baked into the hash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Machine-verifiable.&lt;/strong&gt; Smart contracts can reconstruct the exact hash from the typed data, recover the signer, and verify the authorization on-chain. No ambiguity, no parsing, no custom deserialization logic.&lt;/p&gt;

&lt;p&gt;This combination is why EIP-712 became the backbone of gasless approvals (ERC-2612), meta-transactions, and most of modern DeFi's authorization infrastructure. Uniswap's Permit2 uses it to let users approve token spending with a signature instead of a transaction. Aave uses it for credit delegation. OpenSea used it for gasless NFT listings. The pattern is always the same: user signs structured data off-chain, contract verifies on-chain, and the domain separator ensures that signature can't be replayed anywhere it wasn't intended.&lt;/p&gt;

&lt;p&gt;It's not just a convenience. It's a security primitive. And it's the kind of standard that separates blockchains that are ready for real-world financial applications from those that aren't.&lt;/p&gt;

&lt;p&gt;If you're building on Casper, you're about to start using it too.&lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4afdhb3yk6qfu4i642fu.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4afdhb3yk6qfu4i642fu.jpg" alt="Architecture diagram — EIP-712 signing flow: User signs typed data off-chain (zero cost) → Relayer submits to Casper contract → Contract verifies signature, recovers signer, executes action" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Brought EIP-712 to Casper
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;&lt;code&gt;casper-eip-712&lt;/code&gt;&lt;/a&gt; is a &lt;code&gt;no_std&lt;/code&gt;-compatible Rust crate that brings the full EIP-712 toolkit to Casper. It gives you domain construction, typed struct hashing, encoding helpers, and optional secp256k1 signer recovery. Everything you need to implement the same signature patterns that power the EVM ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building a Domain
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;DomainBuilder&lt;/code&gt; supports both standard EVM fields and Casper-native extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;casper_eip_712&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// EVM-compatible domain, interoperable with ethers.js and MetaMask&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DomainBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyToken"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.chain_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.verifying_contract&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0x11&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Casper-native domain: uses chain_name and contract_package_hash&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DomainBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bridge"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.custom_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"chain_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;DomainFieldValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"casper-test"&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="nf"&gt;.custom_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"contract_package_hash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;DomainFieldValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Bytes32&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0x99&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rrhuw0b3gvbe8ecs8q6.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7rrhuw0b3gvbe8ecs8q6.jpg" alt="Domain separator comparison" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That dual-domain support is intentional. If you're building a bridge that verifies Ethereum-origin signatures, use the EVM-compatible domain. If you're building a Casper-native dApp and want domain fields that make sense for Casper (like &lt;code&gt;chain_name&lt;/code&gt; and &lt;code&gt;contract_package_hash&lt;/code&gt; instead of integer chain IDs and 20-byte addresses), use the custom fields. Same hashing algorithm, same security properties, native semantics for each chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining Custom Typed Structs
&lt;/h3&gt;

&lt;p&gt;Any struct can be EIP-712 hashable by implementing the &lt;code&gt;Eip712Struct&lt;/code&gt; trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Attestation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;claim_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Eip712Struct&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Attestation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;type_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Attestation(address subject,bytes32 claim_hash)"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;type_hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;keccak256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;type_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;encode_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&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;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.extend_from_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;encode_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.subject&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.extend_from_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nf"&gt;encode_bytes32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.claim_hash&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;out&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;Then hashing is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash_typed_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;attestation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The crate ships with prebuilt &lt;code&gt;Permit&lt;/code&gt;, &lt;code&gt;Approval&lt;/code&gt;, and &lt;code&gt;Transfer&lt;/code&gt; structs for common patterns, so you don't have to implement these yourself for standard use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Decisions
&lt;/h3&gt;

&lt;p&gt;A few things worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;no_std&lt;/code&gt; + &lt;code&gt;alloc&lt;/code&gt;&lt;/strong&gt;: The crate is designed for WASM-based contract targets. It works inside Casper smart contracts without pulling in &lt;code&gt;std&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional &lt;code&gt;verify&lt;/code&gt; feature&lt;/strong&gt;: Enable &lt;code&gt;verify&lt;/code&gt; in your &lt;code&gt;Cargo.toml&lt;/code&gt; to get secp256k1 signer recovery via &lt;code&gt;k256&lt;/code&gt;. Leave it off if you only need hashing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framework-agnostic&lt;/strong&gt;: We built &lt;code&gt;casper-eip-712&lt;/code&gt; as a standalone Rust crate, not as a module for any specific framework. This was intentional: any Casper contract can use it, regardless of tooling. But since most contracts on Casper today are developed using &lt;a href="https://odra.dev" rel="noopener noreferrer"&gt;Odra&lt;/a&gt;, the rapid-development smart contracting framework, we made sure it integrates seamlessly. Add it to your &lt;code&gt;Cargo.toml&lt;/code&gt;, import the prelude, and you're signing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Usage: The Bridge
&lt;/h2&gt;

&lt;p&gt;Remember that Halborn audit? Here's the payoff.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://csprbridge.com" rel="noopener noreferrer"&gt;CSPRbridge.com&lt;/a&gt; cross-chain bridge connects Casper to EVM networks. Its core security mechanism is multi-relayer attestation: when tokens move between chains, a threshold of relayers must sign an attestation confirming the transaction. The Casper-side contract then verifies these signatures before minting or releasing tokens.&lt;/p&gt;

&lt;p&gt;Before &lt;code&gt;casper-eip-712&lt;/code&gt;, this verification used hand-rolled encoding: four separate hash functions in &lt;code&gt;crypto.rs&lt;/code&gt;, each manually assembling bytes with &lt;code&gt;keccak256&lt;/code&gt; and &lt;code&gt;encodePacked&lt;/code&gt;-style concatenation. Each one was correct for its specific message type, but each was also bespoke. No shared schema. No domain binding per deployment. No way for a wallet or monitoring tool to introspect what was being signed.&lt;/p&gt;

&lt;p&gt;The audit identified the gap: signatures weren't bound to a specific contract deployment. An attestation for one bridge instance could theoretically be replayed against another. It also flagged the lack of a standardized encoding scheme, which made the system harder to audit, harder to extend, and harder to reason about.&lt;/p&gt;

&lt;p&gt;We didn't just patch the finding. We built infrastructure so that every project on Casper gets this right by default. The bridge is migrating its attestation verification to &lt;code&gt;casper-eip-712&lt;/code&gt;, binding every signature to a specific chain, contract, and protocol version. What used to be four custom hash functions becomes one standard pattern. And critically, any new message type the bridge needs to support (new token standards, new cross-chain operations) follows the same trait implementation. Add your struct, implement &lt;code&gt;Eip712Struct&lt;/code&gt;, and the hashing, encoding, and verification are handled.&lt;/p&gt;

&lt;p&gt;This is what I mean when I say we built infrastructure, not a patch. The next team that builds a bridge, an oracle, or any system that needs cross-chain attestations on Casper doesn't have to solve this problem again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The TypeScript Companion
&lt;/h2&gt;

&lt;p&gt;Smart contracts verify signatures. But someone has to create them first, and that someone is usually a frontend developer writing TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;&lt;code&gt;@casper-ecosystem/casper-eip-712&lt;/code&gt;&lt;/a&gt; is the TypeScript mirror of the Rust crate. It provides the same domain construction, type hashing, and encoding functions, plus signer recovery for client-side verification:&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;hashTypedData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;recoverTypedDataSigner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;PermitTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EIP712Domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PermitMessage&lt;/span&gt;&lt;span class="p"&gt;,&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="s2"&gt;@casper-ecosystem/casper-eip-712&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;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EIP712Domain&lt;/span&gt; &lt;span class="o"&gt;=&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="s2"&gt;PermitToken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1314614895&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;verifyingContract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&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;permit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PermitMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;owner&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;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;spender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;spenderAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="nx"&gt;n&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="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0xffffffff&lt;/span&gt;&lt;span class="nx"&gt;n&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="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&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="c1"&gt;// Sign with ethers.js, standard Ethereum tooling&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;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signTypedData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermitTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;permitPayload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Verify locally before submitting to chain&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hashTypedData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermitTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Permit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;permit&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;recovered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recoverTypedDataSigner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PermitTypes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Permit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sigBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend devs don't need to touch Rust. The TypeScript package produces the exact same hashes and digests as the Rust crate, verified by shared test vectors generated from a single source of truth. Sign in the browser, verify on Casper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo: The Permit/Approve Pattern in Action
&lt;/h2&gt;

&lt;p&gt;Talk is cheap. Let me show you.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/casper-ecosystem/casper-eip-712/tree/master/examples/permit-token" rel="noopener noreferrer"&gt;&lt;code&gt;examples/permit-token&lt;/code&gt;&lt;/a&gt; directory contains a complete working CEP-18 token with gasless permit/approve, the same pattern that powers Uniswap's token approvals, now running on Casper.&lt;/p&gt;

&lt;p&gt;Here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A user signs a Permit off-chain&lt;/strong&gt; using standard Ethereum tooling (ethers.js &lt;code&gt;signTypedData&lt;/code&gt;). Zero cost. No transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A relayer submits the signature&lt;/strong&gt; to the Casper contract, paying the deploy cost on the user's behalf.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The contract verifies the EIP-712 signature&lt;/strong&gt;, recovers the signer's Ethereum address, checks the nonce and deadline, and writes the token allowance. All without the token owner ever submitting a transaction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The demo is a CEP-18 token built with &lt;a href="https://odra.dev" rel="noopener noreferrer"&gt;Odra&lt;/a&gt;. The EIP-712 permit pattern drops in as a regular crate dependency. No special adapters, no glue code. Odra handles the smart contract scaffolding; &lt;code&gt;casper-eip-712&lt;/code&gt; handles the cryptographic verification.&lt;/p&gt;

&lt;p&gt;Run the Rust tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;examples/permit-token
cargo odra &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the TypeScript demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;js &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;span class="nb"&gt;cd &lt;/span&gt;examples/permit-token/demo
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npx tsx demo.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run this demo without a Casper node. Right now. Go.&lt;/p&gt;

&lt;p&gt;The TypeScript demo generates a keypair, signs a permit using ethers.js, verifies it client-side with our TypeScript package, and shows you exactly what the on-chain contract call would look like: the 65-byte signature, the reconstructed digest, and the recovered signer address. The Rust integration tests do the full round-trip inside an Odra test environment: deploy the contract, sign a permit, submit it, verify the allowance was set, and confirm that invalid signatures, expired deadlines, and replayed nonces are rejected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Unlocks for Casper
&lt;/h2&gt;

&lt;p&gt;I didn't write a Rust crate because I was bored on a Saturday night. (Well, partially. But mostly for what it enables.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Gasless Transactions and Relayer Services
&lt;/h3&gt;

&lt;p&gt;The number one UX barrier in crypto is "buy gas first." A new user wants to use your dApp. They don't own CSPR. Under the current model, they bounce. With EIP-712 permits and a relayer service, that user signs an authorization off-chain (free) and the relayer submits it on their behalf, paying the deploy cost. The user interacts with Casper without ever acquiring CSPR upfront. This is how you onboard the next million users. By not asking them to figure out gas fees before they can do anything useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agentic Commerce via x402
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.x402.org/" rel="noopener noreferrer"&gt;x402 protocol&lt;/a&gt; is enabling AI agents to pay for API access and services using HTTP 402 payment flows with stablecoins. Think about that for a second. Autonomous agents, making purchasing decisions, signing payment authorizations. EIP-712 is the natural signing layer for this: structured, domain-separated, human-auditable authorizations that smart contracts can verify. As x402 comes to Casper, &lt;code&gt;casper-eip-712&lt;/code&gt; provides the cryptographic foundation for agents to sign verifiable, scoped authorizations. Not opaque byte blobs. Typed, structured data with clear semantics that a compliance system, a monitoring tool, or a human can read and understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-Chain Interoperability
&lt;/h3&gt;

&lt;p&gt;In a multi-chain world, domain separation isn't a nice-to-have. It's a security requirement. A signature for your mainnet bridge deployment must not be valid against your testnet deployment. An attestation for the ERC-20 locker must not work against the NFT bridge. &lt;code&gt;casper-eip-712&lt;/code&gt;'s &lt;code&gt;DomainBuilder&lt;/code&gt; supports hybrid environments natively: EVM-standard fields for Ethereum-origin signatures, Casper-native fields for Casper-native protocols, and the flexibility to mix custom fields for whatever your architecture needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch Authorization
&lt;/h3&gt;

&lt;p&gt;A relayer collects signed permits from multiple users and submits them in a single deploy. Users get instant, gasless interactions. The relayer amortizes deploy costs. Smart contracts verify each signature independently. This pattern is already standard on Ethereum (Uniswap's Permit2, for example). Now it works on Casper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Non-Crypto-Native Onboarding
&lt;/h3&gt;

&lt;p&gt;Let's be blunt: the current onboarding flow for most blockchain applications is terrible. I &lt;a href="https://dev.to/csprsuite/enabling-web3-adoption-with-cspr-click-8c551875985a"&gt;wrote about this extensively&lt;/a&gt;: the "connect your wallet" gauntlet, the gas token requirement, the 24-word seed phrase anxiety. EIP-712 is a key piece of the puzzle for fixing this. Combined with a relayer architecture, you can build Casper dApps where the user never sees a wallet popup, never buys gas, and never knows they're interacting with a blockchain. They sign a message, a message they can actually read and understand, and the relayer handles the rest. That's the user experience that gets us from 420 million crypto users to a billion.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Big Picture
&lt;/h3&gt;

&lt;p&gt;This isn't just a library. It's a building block that positions Casper to compete for the next wave of adoption, the wave where users don't know they're using a blockchain, and AI agents transact on their behalf. Gasless UX, agentic commerce, cross-chain interop, batch transactions: these are the patterns that the most successful chains will support natively. &lt;code&gt;casper-eip-712&lt;/code&gt; gives Casper that foundation.&lt;/p&gt;

&lt;p&gt;When I look at where crypto is headed (account abstraction, intent-based architectures, agent-driven commerce), every one of those paths runs through structured, domain-separated signing. We're not building for where blockchain is today. We're building for where it's going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build With Us
&lt;/h2&gt;

&lt;p&gt;The crate is open source, published, and ready to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;casper-ecosystem/casper-eip-712&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust Crate:&lt;/strong&gt; &lt;a href="https://crates.io/crates/casper-eip-712" rel="noopener noreferrer"&gt;crates.io/crates/casper-eip-712&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NPM Package:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@casper-ecosystem/casper-eip-712" rel="noopener noreferrer"&gt;@casper-ecosystem/casper-eip-712&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust Docs:&lt;/strong&gt; &lt;a href="https://docs.rs/casper-eip-712/1.0.0/casper_eip_712/" rel="noopener noreferrer"&gt;docs.rs/casper-eip-712&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working Demo:&lt;/strong&gt; &lt;a href="https://github.com/casper-ecosystem/casper-eip-712/tree/master/examples/permit-token" rel="noopener noreferrer"&gt;examples/permit-token&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building on Casper, use it. If you're building on Ethereum and wondering what else is out there, try it. The signatures are the same.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>web3</category>
      <category>ethereum</category>
      <category>rust</category>
    </item>
    <item>
      <title>Casper CEP-78 Enhanced NFT Standard</title>
      <dc:creator>Jonas Pauli</dc:creator>
      <pubDate>Fri, 21 Oct 2022 18:41:32 +0000</pubDate>
      <link>https://dev.to/casperblockchain/casper-cep-78-enhanced-nft-standard-4ibe</link>
      <guid>https://dev.to/casperblockchain/casper-cep-78-enhanced-nft-standard-4ibe</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
Most people only have experience with NFTs in the form of JPEGs and art collections, despite the wide variety of use-cases beyond this implementation. The new enhanced NFT standard on Casper is designed to support more than ordinary NFT collections and even allows for developers to associate real world objects with digital representations in the form of NFTs on the blockchain.&lt;/p&gt;

&lt;p&gt;There are now three different "metadata_types":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Physical&lt;/strong&gt;: The NFT represents a real-world physical item e.g a house.&lt;br&gt;
&lt;strong&gt;Digital&lt;/strong&gt;: The NFT represents a digital item, e.g a unique JPEG or a digital art.&lt;br&gt;
&lt;strong&gt;Virtual&lt;/strong&gt;: The NFT is the virtual representation of a physical notion, e.g a patent or copyright.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article introduces the &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft"&gt;Casper Cep-78 token standard&lt;/a&gt;, which is an upgrade of the deprecated Cep-47 standard. Essentially, the Cep-78 token standard is more flexible and supports “modalities”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Casper NFT Visualizer&lt;/strong&gt;&lt;br&gt;
Thanks to the &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft"&gt;casper-signer&lt;/a&gt; and the &lt;a href="https://github.com/casper-ecosystem/casper-js-sdk"&gt;casper-javascript-sdk&lt;/a&gt;, building Dapps on Casper is achievable. To showcase this, I built a “Casper-Sandbox” demo application using React that is open source and can be found &lt;a href="https://github.com/jonas089/casper-nft-sandbox-demo"&gt;here&lt;/a&gt;. If you want to install and test the react app follow the setup guide. You will need &lt;a href="https://reactjs.org/docs/getting-started.html"&gt;React&lt;/a&gt; and &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04"&gt;Node.js&lt;/a&gt; to run the app.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pQ7l3G6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y35j7p358gx3ixzv21og.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pQ7l3G6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y35j7p358gx3ixzv21og.png" alt="example account on NFT Sandbox" width="720" height="376"&gt;&lt;/a&gt;&lt;br&gt;
The “Casper-Sandbox” is an open-source NFT visualizer built to demonstrate some of the capabilities of the Casper Blockchain and the CEP-78 Standard. The app is still under development but already supports minting of “digital” NFTs. The &lt;a href="https://github.com/jonas089/casper-nft-sandbox-demo/blob/master/README.md"&gt;readme&lt;/a&gt; includes the latest documentation for the project.&lt;br&gt;
&lt;strong&gt;Metadata&lt;/strong&gt;&lt;br&gt;
The structure of an NFTs metadata is defined by a json schema. Cep-78 supports both standardized and custom json schemes. Standardized schemes are easier to integrate, whilst custom schemes can be individualized to suit a projects needs best.&lt;br&gt;
&lt;em&gt;An example for a standardized json schema (CEP78):&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "Example NFT",
  "token_uri": "https://SOME_BACKEND/id",
  "checksum":
"SOME_CHECKSUM"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example the webserver at "token_uri" should return json data containing all relevant information regarding the NFT, such as a url to the image/jpg file, name and description.&lt;/p&gt;

&lt;p&gt;Alternatively, one could define a custom metadata schema to store binary data instead of a weblink as the NFTs metadata.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;An example of custom metadata:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "properties":{
      "nft_name":{
         "name":"some_name",
         "description":"some_description",
         "required":true
      },
      "nft_binary_data":{
         "name":"some_binary_data",
         "description":"some_description",
         "required":true
      },
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;_More examples can be found in the &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/README.md"&gt;readme&lt;/a&gt; of the enhanced NFT standard.&lt;br&gt;
_&lt;br&gt;
&lt;strong&gt;Deploy the Contract&lt;/strong&gt;&lt;br&gt;
In the following, I will explain how to deploy the enhanced NFT standard on Ubuntu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**Dependencies**:
- libssl-dev
- curl
- cmake
- pkg-config
$ sudo apt install libssl-dev curl cmake pkg-config
Setup:
1. install Rust and default to nightly toolchain:
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env
$ rustup toolchain install nightly
$ rustup default nightly
2. install the casper-client
$ cargo install casper-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to compile the Rust smart contract to WebAssembly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;casper@jonas:~/Desktop/cep-78-enhanced-nft-dev$ make prepare
casper@jonas:~/Desktop/cep-78-enhanced-nft-dev$ make build-contract
the compiled contract.wasm will be in ./contract/target/wasm32-unknown-unknown/release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy the compiled contract.wasm to casper testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ casper-client put-deploy --node-address &amp;lt;NODE_ADDRESS&amp;gt; --chain-name casper-test --secret-key &amp;lt;PATH_TO_SECRET_KEY&amp;gt; --payment-amount &amp;lt;GAS_FEE_IN_MOTE&amp;gt; --session-path &amp;lt;PATH_TO_contract.wasm&amp;gt; --session-arg &amp;lt;see below&amp;gt;,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Session Arguments:&lt;/strong&gt;&lt;br&gt;
A list of mandatory session arguments for an NFT contract on Casper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"collection_name": The name of the NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.&lt;/li&gt;
&lt;li&gt;"collection_symbol": The symbol representing a given NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.&lt;/li&gt;
&lt;li&gt;"total_token_supply": The total number of NFTs that a specific instance of a contract will mint passed in as a U64 value. This parameter is required and cannot be changed post installation.&lt;/li&gt;
&lt;li&gt;"ownership_mode": The OwnershipMode modality that dictates the ownership behavior of the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.&lt;/li&gt;
&lt;li&gt;"nft_kind": The NFTKind modality that specifies the off-chain items represented by the on-chain NFT data. This argument is passed in as a u8 value and is required at the time of installation.&lt;/li&gt;
&lt;li&gt;"json_schema": The JSON schema for the NFT tokens that will be minted by the NFT contract passed in as a String. This parameter is required if the metadata kind is set to CustomValidated(4) and cannot be changed post installation.&lt;/li&gt;
&lt;li&gt;"nft_metadata_kind": The metadata schema for the NFTs to be minted by the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.&lt;/li&gt;
&lt;li&gt;"identifier_mode": The NFTIdentifierMode modality dictates the primary identifier for NFTs minted by the contract. This argument is passed in as a u8 value and is required at the time of installation.&lt;/li&gt;
&lt;li&gt;"metadata_mutability": The MetadataMutability modality dictates whether the metadata of minted NFTs can be updated. This argument is passed in as a u8 value and is required at the time of installation.
&lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/README.md"&gt;More&lt;/a&gt; on session args
&lt;strong&gt;Mint an NFT&lt;/strong&gt;
Before we can mint an NFT using our installed contract, we have to find the "contract_hash"of our deploy.
In order to accomplish this, we will have to query the "state-root-hash" after our deploy has been successfully processed, use that "state-root-hash" to query our account and copy the "contract_hash" associated with the "contract_name". ( which in this case will be "nft_contract", as specified in &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/contract/src/constants.rs"&gt;constants.rs&lt;/a&gt;)
&lt;em&gt;Query your account:&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ casper-client get-state-root-hash &amp;lt;node-address&amp;gt;
-&amp;gt; outputs "state-root-hash"
$ casper-client get-account-state --node-address&amp;lt;NODE_ADDRESS&amp;gt; --state-root-hash &amp;lt;STATE_ROOT_HASH&amp;gt; --key &amp;lt;account-hash-YOUR_ACCOUNT_HASH&amp;gt;
-&amp;gt; find "contract_hash" of deploy named "nft_contract" in output and copy it. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Use the "contract_hash"of the deploy to call the mint() and deploy your first NFT to the Casper Blockchain:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A copy of the command I used to mint a Cep-78 digital NFT on Casper, using the standard metadata schema and dummy metadata from the README:
$ casper-client put-deploy \
--node-address http://136.243.187.84:7777 \
--chain-name casper-test \
--secret-key ./private.pem \
--payment-amount 1000000000 \
--session-hash hash-b4b78992e0324be09f174637c3dda2d29cc5c21c44430b72a0943d3ba6d2c827 \
--session-entry-point mint \
--session-arg "token_owner:key='account-hash-5a54f173e71d3c219940dcb9dfec222b024cd81aa7e0672de59ba5fab296448b'" \
--session-arg "token_meta_data:string='{\"name\":\"John Doe\",\"token_uri\":\"https://www.barfoo.cong\",\"checksum\":\"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fc\"}'"
-&amp;gt; outputs a deploy hash.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Get a List of all owned NFTs by Account&lt;/strong&gt;&lt;br&gt;
In order to access the Metadata of an NFT, it is necessary to know which NFTs are owned by a given account. The Cep-78 contract’s named_keys store contain a dictionary named “owned_tokens”.&lt;/p&gt;

&lt;p&gt;Find the Ids or Hashs of NFTs owned by your account. Whether your NFT is identified by a hash identifier or numerical Id depends on the modalityNFTIdentifierModethat defaults to “Ordinal” (numerical instead of hash):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A copy of the command I used to query the NFTs owned by my Account:
$ casper-client get-dictionary-item \
-n http://136.243.187.84:7777 \
-s 256d0445121f1144a09394c739c9baf82b5624b66dced181a0c1c8b8e936652b \
--account-hash hash-b4b78992e0324be09f174637c3dda2d29cc5c21c44430b72a0943d3ba6d2c827 \
--dictionary-name owned_tokens \
--dictionary-item-key 5a54f173e71d3c219940dcb9dfec222b024cd81aa7e0672de59ba5fab296448b
where --dictionary-item-key is set to my account-hash and -s is a new state-root-hash.
A copy of the output:
{
  "id": 6249115604543280689,
  "jsonrpc": "2.0",
  "result": {
    "api_version": "1.4.6",
    "dictionary_key": "dictionary-6bded5cf061dd95463e0064996f24cb88d19a6a7b24962a1347a5392356a35a0",
    "merkle_proof": "[38054 hex chars]",
    "stored_value": {
      "CLValue": {
        "bytes": "[280 hex chars]",
        "cl_type": {
          "List": "String"
        },
        "parsed": [
          "8bc73bf6cfdb48d0e88f16e0c02d5adff6c60a61a4b6bd65349d75fcb7b500d8",
          "0e557acd2b5a43a91c23c2f0e01687cc8a5342e105be22777b7bf97daf757c4f"
        ]
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parsed value is a list of hash identifiers representing NFTs owned by the account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"8bc73bf6cfdb48d0e88f16e0c02d5adff6c60a61a4b6bd65349d75fcb7b500d8",
          "0e557acd2b5a43a91c23c2f0e01687cc8a5342e105be22777b7bf97daf757c4f"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Read NFT Metadata&lt;/strong&gt;&lt;br&gt;
The metadata that is passed as an argument when minting an NFT using CEP-78 is saved in a hashmap on the blockchain, where the key is the hash or numeric identifier, depending on theidentifier_mode modality. The name of the dictionary depends on the metadata_kind modality.&lt;br&gt;
&lt;em&gt;The NFT metadata can be found in the related dictionary:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. "metadata_custom_validated"
2. "metadata_cep78"
3. "metadata_nft721"
4. "metadata_raw"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const client = await new CasperClient(node_addr);
  var product_contract = new Contracts.Contract(client);
  product_contract.setContractHash(cep78_contract_hash);
  const list = [YOUR_NFT_HASH_IDs];
  let meta = [];
  for (item in list) {
    console.log("Item is: ", list[item].toString());
    await product_contract.queryContractDictionary(
      "metadata_custom_validated",
      list[item]
    ).then(response =&amp;gt; {
      meta.push(response.data);
    }).catch(error =&amp;gt; {
      console.log(error);
    })
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This example shows how a javascript application can query a deployed cep-78 instance with custom validated metadata as metadata_kind.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Youtube Workshop&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn to configure and install the CEP-78 smart contract &lt;a href="https://www.youtube.com/watch?v=29eGzDn4HmM&amp;amp;list=PLq1atlGCXMqMgoMPKvMiA219LQXA_iPEI&amp;amp;index=2"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Learn to use the Sandbox application &lt;a href="https://www.youtube.com/watch?v=9Ybp3zZvfx4&amp;amp;list=PLq1atlGCXMqMgoMPKvMiA219LQXA_iPEI&amp;amp;index=2"&gt;here&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
Minting NFTs on Casper is a straight forward process and the enhanced Token standard is a major improvement over the &lt;a href="https://github.com/casper-ecosystem/casper-nft-cep47"&gt;CEP47 Token standard&lt;/a&gt;. It’s a more flexible and future proof implementation, setting a metadata standard which allows for the integration of Casper NFTs in both on- and off-chain applications.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip: When passing metadata or json schemes using the casper-client, the json strings need to be escaped. When deploying a Cep-78 instance, I use &lt;a href="https://jsontostring.com/"&gt;this tool&lt;/a&gt; to escape my json schema.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nft</category>
      <category>blockchain</category>
      <category>opensource</category>
      <category>web3</category>
    </item>
    <item>
      <title>a16z "Can't be Evil" licenses - a practical guide</title>
      <dc:creator>Jonas Pauli</dc:creator>
      <pubDate>Fri, 21 Oct 2022 18:19:22 +0000</pubDate>
      <link>https://dev.to/casperblockchain/a16z-licenses-a-practical-guide-3p17</link>
      <guid>https://dev.to/casperblockchain/a16z-licenses-a-practical-guide-3p17</guid>
      <description>&lt;p&gt;&lt;em&gt;This guide provides detailed documentation on how to install and use a16z “Can’t be Evil” licenses on Casper.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
There are many uncertainties regarding copyright and ownership in the NFT space. Users purchase tokenized avatars and artworks, whilst unaware of the legal situation. Resarachers at the venture capital firm “a16z” have made an effort to solve these issues with their “Can’t be evil” NFT licenses. According to a16z, NFTs need to be licensed, as owning the token Id on the blockchain may not be enough to legally reproduce or display an artwork.&lt;/p&gt;

&lt;p&gt;The a16z “Can’t be evil” NFT licenses include &lt;a href="https://www.plagiarismtoday.com/wp-content/uploads/2022/09/CBE_LicenseChart_FA-1536x864-1-700x394.webp"&gt;sets of rules&lt;/a&gt; regarding ownership and copyright. Rights and permissions granted through the license only apply to the owner of the NFT. Licenses make it easier to clearly communicate which rights are or are not granted to the customer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://a16zcrypto.com/introducing-nft-licenses/"&gt;Read more&lt;/a&gt; on a16z “Can’t be Evil” licenses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart Contracts&lt;/strong&gt;&lt;br&gt;
a16z has already published their licenses on Arweave. Additionally, a16z released this Solidity smart contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
// a16z Contracts v0.0.1 (CantBeEvil.sol)
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./ICantBeEvil.sol";

enum LicenseVersion {
    CBE_CC0,
    CBE_ECR,
    CBE_NECR,
    CBE_NECR_HS,
    CBE_PR,
    CBE_PR_HS
}

contract CantBeEvil is ERC165, ICantBeEvil {
    using Strings for uint;
    string internal constant _BASE_LICENSE_URI = "ar://_D9kN1WrNWbCq55BSAGRbTB4bS3v8QAPTYmBThSbX3A/";
    LicenseVersion public licenseVersion; // return string
    constructor(LicenseVersion _licenseVersion) {
        licenseVersion = _licenseVersion;
    }

    function getLicenseURI() public view returns (string memory) {
        return string.concat(_BASE_LICENSE_URI, uint(licenseVersion).toString());
    }

    function getLicenseName() public view returns (string memory) {
        return _getLicenseVersionKeyByValue(licenseVersion);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165) returns (bool) {
        return
            interfaceId == type(ICantBeEvil).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    function _getLicenseVersionKeyByValue(LicenseVersion _licenseVersion) internal pure returns (string memory) {
        require(uint8(_licenseVersion) &amp;lt;= 6);
        if (LicenseVersion.CBE_CC0 == _licenseVersion) return "CBE_CC0";
        if (LicenseVersion.CBE_ECR == _licenseVersion) return "CBE_ECR";
        if (LicenseVersion.CBE_NECR == _licenseVersion) return "CBE_NECR";
        if (LicenseVersion.CBE_NECR_HS == _licenseVersion) return "CBE_NECR_HS";
        if (LicenseVersion.CBE_PR == _licenseVersion) return "CBE_PR";
        else return "CBE_PR_HS";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to support “Can’t be Evil” licenses in Casper smart contracts, the above contract has been translated to Rust:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#![no_std]
#![no_main]

#[cfg(not(target_arch = "wasm32"))]
compile_error!("target arch should be wasm32: compile with '--target wasm32-unknown-unknown'");
extern crate alloc;

use alloc::{
    string::{String, ToString},
    vec,
};

use casper_types::{
    contracts::NamedKeys, runtime_args, ApiError, CLType, CLValue, ContractHash, EntryPoint,
    EntryPointAccess, EntryPointType, EntryPoints, Parameter, RuntimeArgs, URef,
};

use casper_contract::{
    contract_api::{
        runtime,
        storage::{self},
    },
    unwrap_or_revert::UnwrapOrRevert,
};

#[repr(u16)]
enum A16ZError {
    InvalidLicenseVersion = 0,
}
impl From&amp;lt;A16ZError&amp;gt; for ApiError {
    fn from(e: A16ZError) -&amp;gt; Self {
        ApiError::User(e as u16)
    }
}

const _BASE_LICENSE_URI: &amp;amp;str = "ar://_D9kN1WrNWbCq55BSAGRbTB4bS3v8QAPTYmBThSbX3A/";
const CONTRACT_PACKAGE_HASH: &amp;amp;str = "a16z-contract-hash";
const CONTRACT_HASH_KEY_NAME: &amp;amp;str = "contract_hash";

#[no_mangle]
pub extern "C" fn getLicenseURI() {
    let licenseVersion: u64 = runtime::get_named_arg("_licenseVersion");
    match licenseVersion {
        0 =&amp;gt; licenseVersion,
        1 =&amp;gt; licenseVersion,
        2 =&amp;gt; licenseVersion,
        3 =&amp;gt; licenseVersion,
        4 =&amp;gt; licenseVersion,
        5 =&amp;gt; licenseVersion,
        _ =&amp;gt; runtime::revert(A16ZError::InvalidLicenseVersion),
    };

    let licenseURI: String = String::from(_BASE_LICENSE_URI) + &amp;amp;licenseVersion.to_string();
    let licenseUriCLValue: CLValue = CLValue::from_t(licenseURI).unwrap_or_revert();
    runtime::ret(licenseUriCLValue);
}

#[no_mangle]
pub extern "C" fn getLicenseName() {
    let licenseVersion: u64 = runtime::get_named_arg("_licenseVersion");
    match licenseVersion {
        0 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_CC0")).unwrap_or_revert()),
        1 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_ECR")).unwrap_or_revert()),
        2 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_NECR")).unwrap_or_revert()),
        3 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_NECR_HS")).unwrap_or_revert()),
        4 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_PR")).unwrap_or_revert()),
        5 =&amp;gt; runtime::ret(CLValue::from_t(String::from("CBE_PR_HS")).unwrap_or_revert()),
        _ =&amp;gt; runtime::revert(A16ZError::InvalidLicenseVersion),
    };
}

#[no_mangle]
pub extern "C" fn call() {
    let entry_points = {
        let mut entry_points = EntryPoints::new();
        let getLicenseURI = EntryPoint::new(
            "getLicenseURI",
            vec![Parameter::new("_licenseVersion", CLType::U64)],
            CLType::String,
            EntryPointAccess::Public,
            EntryPointType::Contract,
        );
        let getLicenseName = EntryPoint::new(
            "getLicenseName",
            vec![Parameter::new("_licenseVersion", CLType::U64)],
            CLType::String,
            EntryPointAccess::Public,
            EntryPointType::Contract,
        );
        entry_points.add_entry_point(getLicenseURI);
        entry_points.add_entry_point(getLicenseName);
        entry_points
    };
    let named_keys = {
        let mut named_keys = NamedKeys::new();
        named_keys
    };
    storage::new_contract(
        entry_points,
        Some(named_keys),
        Some(String::from(CONTRACT_PACKAGE_HASH)),
        Some(String::from(CONTRACT_HASH_KEY_NAME)),
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;a16z license URIs ( for NFT-developers )&lt;/strong&gt;&lt;br&gt;
Platforms like Opensea comply with the &lt;a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md"&gt;eip-721 metadata standard&lt;/a&gt;. Learn more &lt;a href="https://docs.opensea.io/docs/metadata-standards"&gt;here&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Where the “Can’t be Evil” license URI is stored depends on which metadata schema or standard makes the most sense for a project to follow. Most NFT platforms on Casper will likely comply with the &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/README.md"&gt;CEP-78 metadata standard&lt;/a&gt;. As a metadata URI is a link to a server that returns JSON data, it makes the most sense to include the license in the data returned by the backend.&lt;/p&gt;

&lt;p&gt;Important: The NFT metadata URI is not the same as the License URI. The License URI is an arweave link to a .doc file, whilst the NFT URI fetches JSON, such as the name, description and image URL from a backend.&lt;/p&gt;

&lt;p&gt;As a16z licenses are quite novel, there is not yet a standardized schema to follow. Depending on the legal situation, it might be appropriate to include a license URI or URL in an NFT’s “description”. Casper supports custom metadata schemata, therefore the license URI could be included in the NFT metadata on mint. However, when using custom metadata, other platforms may not be able to integrate the NFTs without manually adding support for a collection / metadata schema.&lt;/p&gt;

&lt;p&gt;Read more about metadata on Casper &lt;a href="https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/README.md"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;strong&gt;Casper a16z Installation guide&lt;/strong&gt;&lt;br&gt;
Follow the steps below to compile, and deploy the a16z “Can’t be Evil” contract on casper.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the git repository
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chef@jonas:~/Desktop$ git clone https://github.com/jonas089/a16z-casper
chef@jonas:~/Desktop$ cd a16z-casper/contract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Compile the a16z contract
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chef@jonas:~/Desktop/a16z-casper/contract$ cargo build --release --target wasm32-unknown-unknown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;=&amp;gt; compiles contract.wasm to ./target/wasm32-unknown-unknown/release&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mm5EopQh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86gvw7wq3rqn2yqb0djz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mm5EopQh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/86gvw7wq3rqn2yqb0djz.png" alt="project structure" width="671" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy the a16z contract ( to Casper Testnet )
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chef@jonas:~/Desktop/a16z-casper/contract/target/wasm32-unknown-unknown/release$ casper-client put-deploy --node-address NODE_ADDRESS --secret-key PRIVATE_KEY_PATH --payment-amount GAS --chain-name casper-test --session-path contract.wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zxCTteJu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cob8zwuvigiq8iua57vd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zxCTteJu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cob8zwuvigiq8iua57vd.png" alt="explorer snapshot" width="565" height="340"&gt;&lt;/a&gt;&lt;br&gt;
Verify the deploy was successful using the &lt;a href="https://testnet.cspr.live/"&gt;explorer&lt;/a&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---n20-SqG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0r69igb2ht2thg79c7wh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---n20-SqG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0r69igb2ht2thg79c7wh.png" alt="Image description" width="720" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query the contract hash of the installed contract
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chef@jonas:~/Desktop$ casper-client get-state-root-hash -n NODE_ADDRESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;=&amp;gt; outputs a state root hash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chef@jonas:~/Desktop$ casper-client query-global-state -n NODE_ADDRESS -s STATE_ROOT_HASH --key YOUR_ACCOUNT_HASH
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;=&amp;gt; outputs account information, including the contract hash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Call the a16z Contract to get a License URI&lt;/strong&gt;&lt;br&gt;
Query the URI for a “Can’t be Evil” license by calling the “getLicenseURI” endpoint, passing the a16z contract hash and the license version as runtime arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
#[no_mangle]
pub extern "C" fn simulateThirdParty(){
    let _licenseVersion:u64 = 0;
    let contract_hash:ContractHash = runtime::get_named_arg("CONTRACT_HASH");
    let licenseURI:String = runtime::call_contract::&amp;lt;String&amp;gt;(
        contract_hash,
        "getLicenseURI",
        runtime_args!{
            "_licenseVersion" =&amp;gt; _licenseVersion
        }
    );
    // do something with licenseURI
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;runtime::call_contract&lt;/em&gt; takes in the contract hashto call the “getLicenseURI” entry point of the a16z contract.&lt;br&gt;
The “getLicenseURI”entry point will return a URI for the “CBE_CC0” license ( licenseVersion 0 ).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;list of all a16z license versions&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 =&amp;gt; CBE_CC0
1 =&amp;gt; CBE_ECR
2 =&amp;gt; CBE_NECR
3 =&amp;gt; CBE_NECR_HS
4 =&amp;gt; CBE_PR
5 =&amp;gt; CBE_PR_HS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
Thanks to a16z, licensing NFTs is simple and straightforward. Both a Solidity and Rust smart contract is available today and users can start using “Can’t be Evil” licenses on various blockchains now. Licenses are relevant, as the current legal situation regarding NFT copyrights is unclear and users should have an interest in knowing which data they actually own and to what extent they can use it.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>opensource</category>
      <category>crypto</category>
      <category>nft</category>
    </item>
    <item>
      <title>Casper Kafka Event Store Pt 2</title>
      <dc:creator>Mark A. Greenslade</dc:creator>
      <pubDate>Fri, 21 Oct 2022 10:58:46 +0000</pubDate>
      <link>https://dev.to/casperblockchain/casper-kafka-event-store-pt-2-4f1</link>
      <guid>https://dev.to/casperblockchain/casper-kafka-event-store-pt-2-4f1</guid>
      <description>&lt;h2&gt;
  
  
  Building a Kafka Cluster in a Kubernetes Cluster
&lt;/h2&gt;

&lt;p&gt;Carl Sagan quoted that If you wish to make an apple pie from scratch, &lt;strong&gt;you must first invent the universe&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Luckily the universe has already been invented, but we still need to build our Kubernetes cluster to host our Kafka cluster.&lt;/p&gt;

&lt;p&gt;For this POC I chose GCP. They’ve done some good work in minimising the UI. Plus the networking works seamlessly behind the scenes.&lt;/p&gt;

&lt;p&gt;Install &lt;strong&gt;gcloud&lt;/strong&gt; and &lt;strong&gt;kubectl&lt;/strong&gt; and run the following command to create the cluster:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud beta container \
 clusters create "[CLUSTER_NAME]" \
 --project "[PROJECT_NAME]"  \
 --zone "[ZONE]" \
 --machine-type "e2-medium" \
 --num-nodes 9 \
 --disk-size "100"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After about 5 minutes we should have a cluster.&lt;/p&gt;

&lt;p&gt;Now we can add Zookeeper and Kafka.&lt;/p&gt;

&lt;p&gt;Use the installation guide from this GitHub &lt;a href="https://github.com/stormeye2000/cspr-kafka-cluster"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we have no Producers or Consumers configured yet, Kafka will be in a waiting state. No leader has been elected yet. This all happens when topics and partitions are created. More on that later.&lt;/p&gt;
&lt;h3&gt;
  
  
  Things to note in this cluster
&lt;/h3&gt;

&lt;p&gt;Zookeeper is a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/"&gt;StatefulSet&lt;/a&gt; of three replicas. We need consistently named pods in the cluster. If we used a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/"&gt;Deployment&lt;/a&gt;, every time a new pod was instantiated, it would be randomly name with a deployment hash suffix.&lt;/p&gt;

&lt;p&gt;With StatefulSets you get consistent pod names. In this case zookeeper-0, zookeeper-1 and zookeeper-2&lt;/p&gt;

&lt;p&gt;Likewise with the Kafka brokers.&lt;/p&gt;

&lt;p&gt;The Kafka broker StatefulSet starts Kafka.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Lines 2–4 define the Dockerfile, source can be viewed &lt;a href="https://github.com/stormeye2000/cspr-kafka-cluster/blob/master/docker/Dockerfile"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I chose to roll my own Dockerfile to allow more control. There are many Kafka Docker images in the hub, but for this project I needed to be able start Kafka with overridden options.&lt;/p&gt;

&lt;p&gt;Lines 5–8 are allocated resources per pod. I used Kenneth Owens excellent templates &lt;a href="https://github.com/kow3ns/kubernetes-kafka/tree/master/manifests"&gt;here&lt;/a&gt; to configure this POC.&lt;/p&gt;

&lt;p&gt;Lines 12–20 are environment variables. Line 13 sets the internal IP of the newly created pod. Lines 17–20 are standard java options.&lt;/p&gt;

&lt;p&gt;Lines 21 onward are Kafka start up options.&lt;/p&gt;

&lt;p&gt;Line 24 starts Kafka with the default server properties files, we then override these properties in the following lines with a mix of Kubernetes and custom env vars&lt;/p&gt;

&lt;p&gt;Line 25 sets the broker id from the pod hostname, eg pod &lt;em&gt;kafka-broker-1&lt;/em&gt; is assigned broker number 1 (StatefulSets give us this naming convention as discussed above)&lt;/p&gt;

&lt;p&gt;Lines 26–29 set the listeners. The brokers need to know how to communicate with each other internally and with external clients. This is difficult to get right. These settings work and will save a lot of pain. Line 26 tells Kafka to use the default 0.0.0.0 which means listen on all interfaces. Line 27 uses the pod ip env var, KAFKA_POD_IP for the advertised listener. Confluent have a good article on listeners &lt;a href="https://www.confluent.io/en-gb/blog/kafka-listeners-explained/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Line 28 tells Kafka to use the text string ‘INSIDE’ as the inter broker listener name. I assumed that when it sees this string it knows that this is an internal listener.&lt;/p&gt;

&lt;p&gt;Line 29 as this POC is an internal Kafka ensemble we can use PLAINTEXT for the security protocol. This is setting it to no encryption or authourisation. This will be changed to SSL for any production cluster.&lt;/p&gt;

&lt;p&gt;Line 30 uses Kubernetes env vars to point to our zookeeper pods. The zookeeper deployment uses a Kubernetes service for gateway access. This is all we need to configure the broker. This gives us the option of *n *zookeepers. We’re just using 3 in this POC&lt;/p&gt;

&lt;p&gt;After running the steps in on the GitHub &lt;a href="https://github.com/stormeye2000/cspr-kafka-cluster"&gt;page&lt;/a&gt; we will have a sucesfully running Kafka/Zookeeper ensemble within a Kubernetes cluster. The ensemble will be in a waiting state. Part 3 of these articles will discuss and demonstrate how to use the cluster, with Casper node events.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>kafka</category>
      <category>web3</category>
      <category>casper</category>
    </item>
    <item>
      <title>Casper Kafka Event Store Pt 1</title>
      <dc:creator>Mark A. Greenslade</dc:creator>
      <pubDate>Thu, 20 Oct 2022 15:58:11 +0000</pubDate>
      <link>https://dev.to/casperblockchain/casper-kafka-event-store-pt-1-lk8</link>
      <guid>https://dev.to/casperblockchain/casper-kafka-event-store-pt-1-lk8</guid>
      <description>&lt;h2&gt;
  
  
  The Description
&lt;/h2&gt;

&lt;p&gt;Casper nodes emit events on state changes. These events in the platform are categorised into three event stream types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Deploy Events&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finality Signature Event&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Main Events&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within each stream type there are multiple event types such as &lt;strong&gt;DeployAccepted&lt;/strong&gt; or &lt;strong&gt;BlockAdded&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;See the Casper &lt;a href="https://docs.casperlabs.io/dapp-dev-guide/building-dapps/monitoring-events/"&gt;documentation&lt;/a&gt; for a full description.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;As can be seen from the diagram below, there will be n nodes emitting 3 event stream types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Ot890GX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2306/1%2A_O3qGUeJ9rRfae7dswh3vg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Ot890GX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2306/1%2A_O3qGUeJ9rRfae7dswh3vg.png" alt="Casper Node Events" width="880" height="821"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a lot of events.&lt;/p&gt;

&lt;p&gt;Even if the event stream is restricted to one or a group of nodes we are still seeing many events.&lt;/p&gt;

&lt;p&gt;Casper clients use these events to build up a picture of state changes in the node and smart contracts.&lt;/p&gt;

&lt;p&gt;These state changes can notify audit tools of any discrepancies, such as suspicious transactions, asset mutation or chain failure.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  &lt;strong&gt;How can we handle so many events?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To reliably consume these event streams we need a high throughput, highly available messaging service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We need to differentiate the event types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to load balance the event stream types into separate silos (Finality Signature events are the majority of events by many multiples)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to be able to replay the events in the case of any data loss or DR&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need confidence in our architecture&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enter &lt;a href="https://kafka.apache.org"&gt;Kafka&lt;/a&gt;, which will satisfy the concerns above.&lt;/p&gt;

&lt;p&gt;Kafka has concepts such as Brokers, Partitions, Replicas, Topics which will all be discussed in details in later sections.&lt;/p&gt;

&lt;p&gt;For now we just need to know that Kafka will be running n brokers acting as a cluster. The Kafka cluster will use &lt;a href="https://zookeeper.apache.org"&gt;Zookeeper&lt;/a&gt; to orchestrate the brokers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xtIO_VBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ajry044f8MLzRdBDjI21Gcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xtIO_VBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ajry044f8MLzRdBDjI21Gcw.png" alt="Kafka Zookeeper setup" width="880" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kafka uses the leader/follower pattern where it will decide amongst itself who is the leader and who follows. If the leader is lost, a new leader will be elected. An odd number is preferred as is always the case with clusters.&lt;/p&gt;

&lt;p&gt;Like all messaging systems, we need to produce and consume messages, Kafka like RabbitMQ handily names these as Producers and Consumers. Lets look into how these fit into our architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H6nXWZrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3194/1%2AVBmi5Q2PwS2EZmeAviTfSw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H6nXWZrP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3194/1%2AVBmi5Q2PwS2EZmeAviTfSw.png" alt="Event flow" width="880" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple and clean architecture.&lt;/p&gt;

&lt;p&gt;The event streams are read by the producer, any transformations are made, eg text to json, and the event is added to a Kafka topic.&lt;/p&gt;

&lt;p&gt;The consumer will then retrieve this event via its topic and process it accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where can we host this architecture?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io"&gt;Kubernetes&lt;/a&gt;. Whatever the question in DevOps, Kubernetes is usually the answer.&lt;/p&gt;

&lt;p&gt;For all it’s minor annoyances (looking at you YAML), what other system can give us guaranteed uptime, replicated apps, ease of deployment/updates etc etc. What else are we going to use? Docker Swarm….&lt;/p&gt;

&lt;p&gt;So that being said, with K8s we can run multiple instances of the producer and consumer. We can also run the Kafka cluster within the K8s cluster to further guarantee its availability. Here’s what the final architecture diagram looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fv-74cpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4216/1%2Aei4OK2obobdMFjNMl7phFQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fv-74cpy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4216/1%2Aei4OK2obobdMFjNMl7phFQ.png" alt="Proof of concept ready architecture" width="880" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consumer groups are a very useful concept added to our solution. They each read a message from a topic once, so both Consumer Group A and B will both read the same message exactly once. Any other consumers can also read the message (Kafka has a time to live on messages)&lt;/p&gt;

&lt;p&gt;As can be seen, we are writing to both an Audit and UI document store. Audit will be used to replay the event history in case of DR, UI will be a structured store which can be used by any UI or reporting tools.&lt;/p&gt;

&lt;p&gt;Implementation details will follow in the coming articles&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>casper</category>
      <category>blockchain</category>
      <category>eventdriven</category>
    </item>
  </channel>
</rss>
