<?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: Fabian Bormann</title>
    <description>The latest articles on DEV Community by Fabian Bormann (@fabianbormann).</description>
    <link>https://dev.to/fabianbormann</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3909580%2F1bce41dc-19c3-499f-bacc-ca44d0e51095.jpeg</url>
      <title>DEV Community: Fabian Bormann</title>
      <link>https://dev.to/fabianbormann</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fabianbormann"/>
    <language>en</language>
    <item>
      <title>I Have a Toy for You and You Will Like It: How to Play with the UVerify Sandbox</title>
      <dc:creator>Fabian Bormann</dc:creator>
      <pubDate>Thu, 14 May 2026 19:20:34 +0000</pubDate>
      <link>https://dev.to/uverify/i-have-a-toy-for-you-and-you-will-like-it-how-to-play-with-the-uverify-sandbox-204p</link>
      <guid>https://dev.to/uverify/i-have-a-toy-for-you-and-you-will-like-it-how-to-play-with-the-uverify-sandbox-204p</guid>
      <description>&lt;p&gt;If you read the &lt;a href="https://uverify.io/blog/sandbox-yano-yaci-store" rel="noopener noreferrer"&gt;previous article on the sandbox internals&lt;/a&gt;, you already know that there is a local playground, what it is made of, and roughly what it can do. What that article did not cover is how to actually play. This one does.&lt;/p&gt;

&lt;p&gt;We will build a custom certificate template for a fictional institution called &lt;strong&gt;Building Block Academy&lt;/strong&gt;, simulate issuing certificates in bulk for fictional students on the local devnet, evaluate the on-chain costs, and inspect the final issued certificates in the UI. At the end, we will submit the finished template to the public UVerify UI repository so anyone can see &lt;strong&gt;Building Block Academy&lt;/strong&gt;'s student certificates at &lt;code&gt;app.uverify.io&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; 24+&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt;: &lt;code&gt;brew install uv&lt;/code&gt; on macOS or the PowerShell one-liner on Windows&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://deno.com/" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;: for the load test at the end&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://claude.ai/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;: optional, but having an LLM handle the template styling saves a lot of time&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Scaffold a Template for Building Block Academy
&lt;/h2&gt;

&lt;p&gt;The sandbox UI compiles templates at startup from a volume-mounted folder. You do not need the full &lt;code&gt;uverify-ui&lt;/code&gt; source. The &lt;code&gt;template add&lt;/code&gt; command scaffolds everything for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run sandbox.py template add BuildingBlockCertificate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node.js is required here because the UVerify CLI runs via &lt;code&gt;npx&lt;/code&gt;. The command creates &lt;code&gt;sandbox/custom-ui-templates/BuildingBlockCertificate/&lt;/code&gt; with a working React component and registers it in &lt;code&gt;additional-templates.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open the generated file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open sandbox/custom-ui-templates/BuildingBlockCertificate/src/Certificate.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scaffold gives you a minimal but complete template that already renders its certificate hash, metadata, and the standard UVerify timestamp. It works out of the box. The next step is making it look like it belongs to Building Block Academy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Let Claude Design It
&lt;/h2&gt;

&lt;p&gt;This is where the UVerify Claude skill comes in. Install it once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add UVerify-io/uverify-claude-skill
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;uverify@uverify-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in any Claude Code session opened at the &lt;code&gt;uverify-examples&lt;/code&gt; folder, type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/uverify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude now knows the full &lt;code&gt;@uverify/core&lt;/code&gt; template API: the &lt;code&gt;Template&lt;/code&gt; base class, &lt;code&gt;layoutMetadata&lt;/code&gt;, &lt;code&gt;render()&lt;/code&gt;, the &lt;code&gt;UVerifyMetadata&lt;/code&gt; and &lt;code&gt;UVerifyCertificateExtraData&lt;/code&gt; types, theming, and the &lt;code&gt;uv_url_&lt;/code&gt; prefix for keeping personal data off-chain.&lt;/p&gt;

&lt;p&gt;Describe what you want. Something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want a certificate template for Building Block Academy, an online blockchain education platform. Their landing page uses a dark navy background, gold accents, and a monospace font for hashes. The certificate should show the graduate's name, the course title, the completion date, and a short skills summary. The graduate's name should not be stored on-chain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude will read &lt;code&gt;Certificate.tsx&lt;/code&gt;, understand the &lt;code&gt;layoutMetadata&lt;/code&gt; keys you need, and rewrite the component. The graduate's name goes into a &lt;code&gt;uv_url_recipientName&lt;/code&gt; field so it stays off-chain but is still visible when someone visits the certificate URL. Everything else (course title, completion date, skills) gets stored as metadata.&lt;/p&gt;

&lt;p&gt;From there, iterate freely. Ask Claude to adjust the font, swap the color scheme, add the academy logo as an SVG inline, or tighten the layout for mobile. The skill knows which props come from &lt;code&gt;metadata&lt;/code&gt;, which come from &lt;code&gt;extra&lt;/code&gt;, and which come from &lt;code&gt;certificate&lt;/code&gt;, so you will not waste time debugging undefined values.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Use the Local UVerify UI to Issue a Test Certificate
&lt;/h2&gt;

&lt;p&gt;Once you are happy, start the sandbox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run sandbox.py start &lt;span class="nt"&gt;--clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt;, click &lt;strong&gt;Create&lt;/strong&gt;, and enter a fictional student and certificate ID, for example &lt;code&gt;Building-Block-Academy-00112233-998877665&lt;/code&gt;. Select your template from the Certificate Template dropdown, fill in the form fields, and click &lt;strong&gt;Use Demo Wallet&lt;/strong&gt;. The Demo Wallet is a disposable wallet that gets funded automatically at that point. The certificate confirms on-chain in a second or two once you click &lt;strong&gt;Create Trust Certificate&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Create a Data Plan
&lt;/h2&gt;

&lt;p&gt;This was a single certificate. The real fun starts when you issue hundreds or thousands of certificates to see how the system performs at scale and what the on-chain costs look like. The simulator generates realistic bulk metadata from a &lt;em&gt;plan&lt;/em&gt; file. Copy the example and shape it for Building Block Academy:&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;cp &lt;/span&gt;sandbox/simulator/plan.example.json sandbox/simulator/plan.buildingblock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;plan.buildingblock.json&lt;/code&gt;. A plan that fits the template you just built might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"courseName"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"one-of"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"values"&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="s2"&gt;"Cardano Fundamentals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Smart Contract Development with Aiken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"DeFi Protocol Design"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Blockchain Security"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NFT Engineering"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Governance and DRep Participation"&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;"completedAt"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"random-string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"202[45]-[01][0-9]-[0-2][0-9]"&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;"grade"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"one-of"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nl"&gt;"values"&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;"Distinction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Merit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pass"&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;"creditsEarned"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"random-number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"range"&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;"min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issuer"&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;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"static"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Building Block Academy"&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;Plan files follow &lt;code&gt;plan*.json&lt;/code&gt; naming and are gitignored (except &lt;code&gt;plan.example.json&lt;/code&gt;), so your local plans stay local.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Run the Simulator
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run sandbox.py simulate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template&lt;/span&gt; BuildingBlockCertificate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--plan&lt;/span&gt; sandbox/simulator/plan.buildingblock.json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--amount&lt;/span&gt; 1500 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--batch-size&lt;/span&gt; 15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The simulator generates 1,500 metadata files, then submits them in batches of 15 certificates per transaction. A wallet is created automatically on first run and funded from the sandbox faucet with three UTxOs of 500 ADA each, which is more than enough. The output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[100/100] Submitting 15 certificate(s) …
  fe418affb5b3667aff7b95084eb8f80d9cc107e8d3492cbbaf6b1b6a7b4e87a2
  fe55c96ac1c9aa5adefc0d1d537a33bc0fcee078f1b26743b48f944481293611
  fe645b6d1028311cdeea7fd6843dea1954c77e8f402b478d7f8c5951fcf52602
  fedc52f9d7ff76d120f95d15350dcf7c335544594f049bf3061939f4a7768865
  fef65cd8837ec08ac03323592f139577565329c6f8f3498849accb045e42457c
  ff611fa073f82d8f431a2f5a75d9b9bdd2393da02ed77482f30a5c555e7e2906
  ff68fd08e764def25c9260549cd6980243e9f722718813aae9685fc63f8042e8
  ff7eb54740fbb0603fd93ae34c13aaa5addcd1ddb25dcaa4b5ad88b868d01f78
  ff8f452b8669ce0dd54488254bd5fc58e4649099d8f957a1f64da8d8b524896b
  ffa736097fbb0b172a51f6d8ee4a387233363a21d9858419badc7d31a019b797
  ffc76932e5986de882a0930114f70c05b2c538581529cb6a0f78ec23c184d8a2
  ffddf56aa793c118b559524ea7166e42dbb4fb144ce8c403338ec5c6cd49f192
  ffecfc988dfd16b38057b14d87bfb7f4a490459c63ca330c62c7a6eb0f5ce4e0
  fff9e33a293613dcf009711c9d355bd1bd31d71bef0117fa31ac125f7ca99d91
  fffdcca1145af6e495fd543a6999c8f5cb6d5e2c16cae5fa4e8d998acf1c67be
  tx:  5a79d808ea1ed3d63ad919b7a0f88ca22bd674a76c1f99fd8f440e02187f008d
  fee: 0.938905 ADA
  Waiting for confirmation …
  Confirmed ✓

──────────────────────────────────────────────────
Transactions : 100
Certificates : 1500
Total fees   : 105.029809 ADA
Results      : results.json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your machine goes to sleep mid-run, the simulator saves progress to &lt;code&gt;results.json&lt;/code&gt; after every confirmed transaction. On the next run it asks whether to continue or start over. Pick &lt;strong&gt;y&lt;/strong&gt; and it skips the already-submitted hashes without resubmitting anything.&lt;/p&gt;

&lt;p&gt;Batch size affects cost. Larger batches pack more certificates per transaction and drive the per-certificate fee down. The practical ceiling is around 70-80 certificates per transaction depending on metadata size, after which Plutus ExUnits become the limiting factor rather than the transaction size limit. If you just need a fingerprint and an Arweave hash or IPFS CID, you can fit more certificates per transaction and reduce costs further. Play around with it and see how it affects the total fees.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Look at What You Made
&lt;/h2&gt;

&lt;p&gt;Grab any certificate hash from the output (or from &lt;code&gt;sandbox/simulator/results.json&lt;/code&gt;) and open it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3000/verify/fe418affb5b3667aff7b95084eb8f80d9cc107e8d3492cbbaf6b1b6a7b4e87a2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your Building Block Academy template renders with the metadata from that specific certificate: course name, grade, credits, date. The timestamp is the slot from the confirmed block. The issuer is the wallet address that signed the transaction. All of it is pulled directly from on-chain data. No database, no backend state.&lt;/p&gt;

&lt;p&gt;You can also browse the raw transactions in Yaci Viewer at &lt;code&gt;http://localhost:3001&lt;/code&gt; and inspect the UTxOs in Yaci Store at &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Share It with the World
&lt;/h2&gt;

&lt;p&gt;The sandbox is great for development, but the real UVerify deployment at &lt;code&gt;app.uverify.io&lt;/code&gt; can host your template too. To get it included:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your template to a public GitHub repository.&lt;/li&gt;
&lt;li&gt;Pin an exact commit hash (no branch names or tags).&lt;/li&gt;
&lt;li&gt;Open an issue on the &lt;a href="https://github.com/UVerify-io/uverify-ui/issues/new?template=add-external-template.yaml" rel="noopener noreferrer"&gt;uverify-ui repository&lt;/a&gt; using the &lt;strong&gt;Add External Template&lt;/strong&gt; issue template.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The template asks for the repo URL, the pinned commit hash, the path to &lt;code&gt;Certificate.tsx&lt;/code&gt;, a description of the use case, and a checklist confirming local testing. Submissions that pass the checklist review get added to &lt;code&gt;additional-templates.json&lt;/code&gt; and become available at &lt;code&gt;app.uverify.io&lt;/code&gt; for anyone to use. You can restrict who sees the template by adding a whitelist to the &lt;code&gt;Certificate.tsx&lt;/code&gt; template class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;whitelist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addr1qyleluql6elu7sktvncqfufnq675hlt9z922ah9sm45dmp7kjn0vsay0vq28379mczjmglmam3svuxyka0tyw0uchwjqmxmhg3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;addr_test1qqleluql6elu7sktvncqfufnq675hlt9z922ah9sm45dmp7kjn0vsay0vq28379mczjmglmam3svuxyka0tyw0uchwjqcsxhyw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only certificates issued by one of those addresses will be visible in the UI.&lt;/p&gt;




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

&lt;p&gt;You now have a running local Cardano devnet, a custom certificate template designed with AI assistance, and 1,500 demo certificates on-chain. Total time: an afternoon at most, probably less.&lt;/p&gt;

&lt;p&gt;The sandbox resets cleanly with &lt;code&gt;uv run sandbox.py start --clean&lt;/code&gt; whenever you want a fresh state. Your template files persist in &lt;code&gt;sandbox/custom-ui-templates/&lt;/code&gt; and survive the reset.&lt;/p&gt;

&lt;p&gt;If something breaks or you want to show off what you built, the &lt;a href="https://discord.gg/Dvqkynn6xc" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; is the right place. Full SDK and API documentation is at &lt;a href="https://docs.uverify.io" rel="noopener noreferrer"&gt;docs.uverify.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now go build something real with it.&lt;/p&gt;

</description>
      <category>cardano</category>
      <category>tutorial</category>
      <category>certification</category>
      <category>devtools</category>
    </item>
    <item>
      <title>What a Playground: Building a Blockchain Sandbox with Yano and Yaci Store</title>
      <dc:creator>Fabian Bormann</dc:creator>
      <pubDate>Mon, 04 May 2026 21:02:05 +0000</pubDate>
      <link>https://dev.to/uverify/what-a-playground-building-a-blockchain-sandbox-with-yano-and-yaci-store-16lo</link>
      <guid>https://dev.to/uverify/what-a-playground-building-a-blockchain-sandbox-with-yano-and-yaci-store-16lo</guid>
      <description>&lt;h2&gt;
  
  
  The Problem with Local Blockchain Development
&lt;/h2&gt;

&lt;p&gt;Developing against a live blockchain network is slow by default. Transactions confirm in seconds at best. Reproducing a precise on-chain state for testing requires replaying a sequence of transactions in the right order, signed by the right keys.&lt;/p&gt;

&lt;p&gt;The alternatives are mocking the chain or stubbing the indexer. Both trade one problem for another. You end up testing against a model of the blockchain rather than the blockchain itself. That gap has a way of hiding bugs until the worst possible moment.&lt;/p&gt;

&lt;p&gt;For UVerify, we needed something better. The UVerify sandbox built with &lt;a href="https://github.com/bloxbean/yano" rel="noopener noreferrer"&gt;Yano&lt;/a&gt; and &lt;a href="https://github.com/bloxbean/yaci-store" rel="noopener noreferrer"&gt;Yaci Store&lt;/a&gt; is the result.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;The UVerify sandbox runs six Docker services. Three of them are the interesting ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yano&lt;/strong&gt; is a &lt;a href="https://github.com/bloxbean/yano/tree/main/node-app" rel="noopener noreferrer"&gt;local running Java Cardano node&lt;/a&gt;. It produces blocks, exposes a Cardano node-to-node (N2N) port for downstream indexers, and provides a Blockfrost-compatible REST API. It also ships with a snapshot API that lets you take a named checkpoint of the full RocksDB chain state and restore it later. That snapshot mechanism is the foundation everything else is built on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yaci Store&lt;/strong&gt; is a full Cardano chain indexer, also from bloxbean. It connects to Yano's N2N port, syncs the chain from genesis, and exposes a rich REST API covering UTxOs, transactions, assets, epochs, staking pools, and governance data. The sandbox runs Yaci Store as a standalone Docker container on port 8080 with its own PostgreSQL schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yaci Viewer&lt;/strong&gt; is a block explorer built on top of Yaci Store. It runs at port 3001 and gives you a visual browser for every block, transaction, and UTxO the local devnet has produced. When you submit a test transaction and want to inspect its inputs and outputs, Yaci Viewer is where you look.&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%2Fct13p7nrwphrfbcultj7.png" 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%2Fct13p7nrwphrfbcultj7.png" alt="Yaci Viewer showing a transaction on the local devnet" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yaci Store exposes a rich REST API documented via Swagger UI at &lt;code&gt;http://localhost:8080/swagger-ui/index.html&lt;/code&gt;. The API surface covers UTxOs, transactions, assets, epochs, staking pools, governance, and more.&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%2Fg3d6mb5n6qmwjz0aylpl.png" 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%2Fg3d6mb5n6qmwjz0aylpl.png" alt="Yaci Store Swagger UI showing the available API endpoints" width="800" height="606"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UVerify UI             http://localhost:3000
UVerify Backend        http://localhost:9090
UVerify API (Swagger)  http://localhost:9090/swagger-ui/index.html
Yaci Viewer            http://localhost:3001
Yaci Store API         http://localhost:8080
Yaci Store (Swagger)   http://localhost:8080/swagger-ui/index.html
Yano devnet API        http://localhost:7070/q/swagger-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Snapshot: No Private Keys, No Transaction Replay
&lt;/h2&gt;

&lt;p&gt;The most important property of the sandbox is what you do not have to do when you start it.&lt;/p&gt;

&lt;p&gt;You do not need the private keys that were used to deploy the smart contracts. You do not need to replay the bootstrap sequence that funded the service wallet, initialized the proxy contract, or registered the bootstrap datum on-chain. All of that state is already present in the snapshot. Starting the sandbox restores it instantly.&lt;/p&gt;

&lt;p&gt;The snapshot is a RocksDB checkpoint taken with Yano's snapshot API after a &lt;code&gt;bootstrap.sh&lt;/code&gt; script ran through the full initialization sequence on a fresh chain. The resulting directory is bundled into the Yano Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"bloxbean-yano:/app/snapshots/uverify-base-state"&lt;/span&gt; ./yano/snapshots/
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; uverify/sandbox-node:latest ./yano/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;sandbox.sh start&lt;/code&gt; runs and finds no existing chainstate volume, it seeds the Docker volume from that bundled snapshot before starting any services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CHAINSTATE_VOLUME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/chainstate"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  uverify/sandbox-node:latest &lt;span class="se"&gt;\&lt;/span&gt;
  sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cp -a /app/snapshots/uverify-base-state/checkpoint/. /chainstate/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From that point forward, Yano starts from a chain that already has every contract deployed and every funding transaction confirmed. The UVerify backend connects, Yaci Store syncs from slot 0, and the whole environment is ready without you having to own, manage, or even know about the service wallet mnemonic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wall-Clock Catch-Up
&lt;/h2&gt;

&lt;p&gt;There is one subtlety with restoring a snapshot: the chain stopped at a specific slot in the past. Cardano's KES (Key Evolving Signature) protocol has time-based validity windows. If the devnet node tries to produce blocks as if no time had passed, it will eventually fail key evolution checks.&lt;/p&gt;

&lt;p&gt;Yano solves this with a single API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:7070/api/v1/devnet/epochs/catch-up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This advances the local chain forward through all the intermediate epochs to reach the current wall-clock time. It runs in seconds regardless of how long ago the snapshot was taken. The &lt;code&gt;sandbox.sh&lt;/code&gt; script calls it automatically after the node comes up, so by the time the rest of the services are healthy, the devnet is producing blocks at the correct epoch and slot.&lt;/p&gt;

&lt;p&gt;This is the piece that makes the sandbox work correctly whether you started it an hour after the last snapshot was built or six months later.&lt;/p&gt;




&lt;h2&gt;
  
  
  Yaci Store as an Embedded Library
&lt;/h2&gt;

&lt;p&gt;The standalone Yaci Store container handles the block explorer use case. But the UVerify backend has a different requirement: it needs to react to specific UTxOs arriving on-chain in real time, not poll a REST API.&lt;/p&gt;

&lt;p&gt;The bloxbean ecosystem provides a &lt;code&gt;yaci-store-spring-boot-starter&lt;/code&gt; library that embeds the Yaci Store indexing pipeline directly into a Spring Boot application. The UVerify backend uses this to run its own internal indexer alongside the application code.&lt;/p&gt;

&lt;p&gt;The backend pulls in four Yaci Store starters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yaci-store-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yaci-store-utxo-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yaci-store-transaction-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;yaci-store-script-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To hook into the indexing pipeline, the backend provides a custom &lt;code&gt;UVerifyStorage&lt;/code&gt; that extends &lt;code&gt;UtxoStorageImpl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@Profile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"!disable-indexer"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UVerifyStorage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;UtxoStorageImpl&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;saveUnspent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressUtxo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;addressUtxoList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressUtxo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;processedByUVerifyCore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;cardanoBlockchainService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processAddressUtxos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressUtxoList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressUtxo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;processedByExtensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;extensionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;processAddressUtxos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressUtxoList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressUtxo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;processedByUVerifyProxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;hasBeenProcessedByUVerifyProxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addressUtxoList&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AddressUtxo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allProcessed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;allProcessed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processedByUVerifyCore&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;allProcessed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processedByExtensions&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;allProcessed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processedByUVerifyProxy&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;allProcessed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveUnspent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;allProcessed&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;deleteUnspentBySlotGreaterThan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cardanoBlockchainService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;handleRollbackToSlot&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;extensionManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;handleRollbackToSlot&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time a new block arrives, Yaci Store calls &lt;code&gt;saveUnspent&lt;/code&gt; with the list of new UTxOs. &lt;code&gt;UVerifyStorage&lt;/code&gt; routes each UTxO through the core processing pipeline, the extension manager, and the proxy contract filter. Only UTxOs relevant to UVerify contracts are persisted. Rollbacks are handled the same way.&lt;/p&gt;

&lt;p&gt;In the sandbox, the backend is pointed at Yano's N2N port via &lt;code&gt;application-devnet.yml&lt;/code&gt;. The same code runs unchanged against preprod and mainnet by simply changing the target node host, port, and protocol magic. No conditional logic, no environment-specific branches.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building and Destroying
&lt;/h2&gt;

&lt;p&gt;Starting the sandbox is a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./sandbox.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the chainstate volume already exists from a previous run, it resumes from where it left off. If you want to wipe everything and start from a clean snapshot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./sandbox.sh start &lt;span class="nt"&gt;--clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This stops all services, deletes the chainstate volume and the PostgreSQL data, and re-seeds from the bundled snapshot. The whole reset takes about a minute. When it finishes, every service is running and all URLs are printed to the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Service                     URL
  ─────────────────────────   ──────────────────────────────────────────
  UVerify UI                  http://localhost:3000
  UVerify Backend             http://localhost:9090
  API docs (Swagger)          http://localhost:9090/swagger-ui/index.html
  Chain viewer                http://localhost:3001
  Yaci Store API              http://localhost:8080
  Yaci Store (Swagger)        http://localhost:8080/swagger-ui/index.html
  Yano devnet API             http://localhost:7070/q/swagger-ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get back a pristine environment with all contracts deployed, all wallets funded, and the chain caught up to wall time. The snapshot is deterministic, so the starting state is always identical no matter how many times you reset.&lt;/p&gt;




&lt;h2&gt;
  
  
  Faucet Mechanics
&lt;/h2&gt;

&lt;p&gt;The sandbox includes a faucet wallet funded during the bootstrap sequence. When running examples, you request funds through the UVerify backend:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UVerifyClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:9090&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signTx&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fundWallet&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The backend faucet uses a &lt;code&gt;FAUCET_MNEMONIC&lt;/code&gt; wallet to build and submit a real Cardano transaction. The transaction is confirmed on-chain, indexed by the embedded Yaci Store, and the UTxO is visible in Yaci Viewer.&lt;/p&gt;

&lt;p&gt;Yano also exposes a direct fund endpoint at &lt;code&gt;POST /api/v1/devnet/fund&lt;/code&gt; that injects UTxOs into the ledger state directly, without creating a transaction. This is useful during the bootstrap process when you need to seed wallets before any application logic is running. For normal example usage, the backend faucet is the right choice: it produces real confirmed transactions with real tx hashes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running the Examples
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/UVerify-io/uverify-examples" rel="noopener noreferrer"&gt;uverify-examples&lt;/a&gt; repository contains nine examples across TypeScript, Python, and Java. Every example is self-contained: no shared utilities, no build system setup. Each one targets the sandbox by default.&lt;/p&gt;

&lt;p&gt;TypeScript examples run with &lt;a href="https://deno.com/" rel="noopener noreferrer"&gt;Deno&lt;/a&gt;:&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;uverify-examples/typescript/diploma
deno run &lt;span class="nt"&gt;-A&lt;/span&gt; index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python examples use &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; with inline PEP 723 dependency declarations:&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;uverify-examples/python/diploma
uv run main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Java examples use &lt;a href="https://www.jbang.dev/" rel="noopener noreferrer"&gt;JBang&lt;/a&gt; with &lt;code&gt;//DEPS&lt;/code&gt; headers:&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;uverify-examples/java/diploma
jbang Diploma.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each example creates a wallet, requests funds from the faucet, issues a certificate, and prints the transaction hash and a verification URL. The wallet mnemonic is persisted to a local file so subsequent runs reuse the same address. You can watch each transaction arrive in Yaci Viewer at &lt;code&gt;http://localhost:3001&lt;/code&gt; while the example is running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The sandbox requires Docker. Everything else is handled automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/UVerify-io/uverify-examples.git
&lt;span class="nb"&gt;cd &lt;/span&gt;uverify-examples
./sandbox.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the complete setup. All six services start from the snapshot, the chain advances to wall time, and the URLs are printed to the terminal.&lt;/p&gt;

&lt;p&gt;If you run into an issue or want to discuss the tooling, join the &lt;a href="https://discord.gg/Dvqkynn6xc" rel="noopener noreferrer"&gt;Discord community&lt;/a&gt; or open an issue on &lt;a href="https://github.com/UVerify-io/uverify-examples" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The full SDK and API documentation is at &lt;a href="https://docs.uverify.io" rel="noopener noreferrer"&gt;docs.uverify.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>cardano</category>
      <category>sandbox</category>
      <category>java</category>
    </item>
  </channel>
</rss>
