<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Kuna Labs Blog]]></title><description><![CDATA[My personal Substack]]></description><link>https://blog.kunalabs.io</link><image><url>https://substackcdn.com/image/fetch/$s_!uOmJ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2075d477-55c3-4e64-a692-9dcfd1d56eb7_144x144.png</url><title>Kuna Labs Blog</title><link>https://blog.kunalabs.io</link></image><generator>Substack</generator><lastBuildDate>Tue, 21 Apr 2026 23:35:41 GMT</lastBuildDate><atom:link href="https://blog.kunalabs.io/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Kuna Labs]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[kunalabs@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[kunalabs@substack.com]]></itunes:email><itunes:name><![CDATA[Kuna Labs]]></itunes:name></itunes:owner><itunes:author><![CDATA[Kuna Labs]]></itunes:author><googleplay:owner><![CDATA[kunalabs@substack.com]]></googleplay:owner><googleplay:email><![CDATA[kunalabs@substack.com]]></googleplay:email><googleplay:author><![CDATA[Kuna Labs]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[sui-client-gen v0.5.0]]></title><description><![CDATA[Ready for What's Next]]></description><link>https://blog.kunalabs.io/p/sui-client-gen-v050</link><guid isPermaLink="false">https://blog.kunalabs.io/p/sui-client-gen-v050</guid><dc:creator><![CDATA[Kuna Labs]]></dc:creator><pubDate>Wed, 14 Jan 2026 20:29:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!uOmJ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2075d477-55c3-4e64-a692-9dcfd1d56eb7_144x144.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>sui-client-gen</strong> is a TypeScript SDK code generator for Sui Move smart contracts. It generates type-safe TypeScript client SDKs from Move source code or on-chain packages&#8212;no IDLs or ABIs required.</p><p>v0.5.0 is a major release that prepares sui-client-gen for Sui&#8217;s evolving ecosystem:</p><ul><li><p><strong>New data interfaces</strong> - Native support for gRPC and GraphQL clients alongside JSON-RPC</p></li><li><p><strong>New package manager</strong> - Built on `move_package_alt` with multi-environment support</p></li><li><p><strong>Agentic coding ready</strong> - Both the generator codebase and the generated SDKs are optimized for AI-assisted development, with comprehensive tests and dynamic environment switching for automated test suites</p></li></ul><h2>Enum Support</h2><p>Move 2024 Edition introduced enums in mid-2024, but sui-client-gen lagged behind. Users with enum types in their contracts couldn&#8217;t use the tool, and newer versions of sui-framework (which now use enums internally) were incompatible.</p><p>v0.5.0 adds first-class enum support. All three variant types are handled:</p><ul><li><p><strong>Unit variants</strong>:  <code>enum Status { Active, Inactive }</code></p></li><li><p><strong>Struct variants</strong>: <code>enum Action { Transfer { to: address, amount: u64 } }</code></p></li><li><p><strong>Tuple variants</strong>: <code>enum Result { Ok(T), Err(u64) }</code></p></li></ul><p>Generated TypeScript includes full type discrimination, BCS encoding/decoding, and the same reified type patterns you&#8217;re used to for structs.</p><h2>Multi-Environment Code Generation</h2><p>Generate a single SDK that works across mainnet, testnet, devnet, localnet, or custom environments.</p><pre><code>import { setActiveEnv } from &#8220;./_envs&#8221;;
setActiveEnv(&#8221;mainnet&#8221;);
// ... all SDK calls now use mainnet addresses
setActiveEnv(&#8221;testnet&#8221;);
// ... now using testnet addresses</code></pre><h3>Why This Matters</h3><p><strong>Dynamic environment switching</strong> - Apps and wallets that operate across multiple networks can switch at runtime using the same generated code.</p><p><strong>Testing with ephemeral environments</strong> - When you spin up a local test environment, you need all package IDs and type origins to point to your ephemeral deployment. This is critical for agentic coding workflows - the SDK can now be pointed at test deployments dynamically, enabling AI tools like Claude Code to run your test suite against fresh deployments.</p><p><strong>Native integration with sui_package_alt</strong> - Environments are defined in your Move.toml and sui-client-gen reads them directly.</p><h3>Compile-Time Compatibility Checking</h3><p>During generation, we verify that struct and function signatures are compatible across all environments. If there&#8217;s a mismatch - say, a struct has different fields on mainnet vs testnet - generation fails with a clear error. This prevents subtle decoding bugs at runtime.</p><p>But we&#8217;re flexible where it makes sense: structs, enums, or functions that exist only in one environment (e.g., test helpers) are allowed. The compatibility check only fails on <em>conflicting</em> definitions, not <em>missing</em> ones.</p><h2>Architecture Refactor: IR-Based Code Generation</h2><p>The biggest internal change in v0.5.0 is a complete rewrite of the code generation pipeline.</p><p><strong>Before:</strong> We used [genco](https://github.com/udoprog/genco), a quasi-quoting library with Rust macros. The code was terse but esoteric&#8212;intimidating to contributors unfamiliar with Rust macro syntax.</p><p><strong>After:</strong> A clean IR (Intermediate Representation) architecture that separates concerns:</p><pre><code>              &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
              &#9474;     Move Model      &#9474;
              &#9474; structs/enums/funcs &#9474;
              &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
                         &#9474;
         &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9532;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
         &#9660;               &#9660;               &#9660;
   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
   &#9474; TypeScript&#9474;   &#9474;   Rust    &#9474;   &#9474;  Python   &#9474;
   &#9474;    IR     &#9474;   &#9474; (planned) &#9474;   &#9474;    ...    &#9474;
   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
         &#9660;               &#9660;               &#9660;
   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;   &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
   &#9474;  .ts      &#9474;   &#9474;   .rs     &#9474;   &#9474;   .py     &#9474;
   &#9474;  files    &#9474;   &#9474;           &#9474;   &#9474;           &#9474;
   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;   &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></pre><h3>Why This Matters</h3><p><strong>Readable code</strong> - The IR layer is plain Rust structs. No macros, no magic. Contributors can understand and modify the codebase without deep Rust expertise.</p><p><strong>Testable</strong> - IR enables snapshot testing at the right level of abstraction. We can test code generation without spinning up RPC connections or compiling Move packages.</p><p><strong>Agentic-friendly</strong> - AI coding assistants are dramatically more effective with this architecture. Clear separation of concerns means the AI can focus on one layer at a time.</p><p><strong>Multi-language support</strong> - The architecture paves the way for Rust SDK generation (planned for a future release). The Move model is shared; only the IR and emit layers are language-specific.</p><h2>JSDoc Documentation from Move Comments</h2><p>Documentation comments in your Move source code now flow through to generated TypeScript.</p><p>Move:</p><pre><code>/// Creates a new liquidity pool with the given parameters.
/// Returns the pool object and LP tokens.
#[deprecated]
public fun create_pool&lt;A, B&gt;(/* ... */) { /* ... */ }</code></pre><p>Becomes:</p><pre><code>/**
 * Creates a new liquidity pool with the given parameters.
 * Returns the pool object and LP tokens.
 * @deprecated
 */
export function createPool&lt;A, B&gt;(/* ... */) {
  /* ... */
}</code></pre><p>This improves IDE autocomplete, hover documentation, and makes the generated SDK more discoverable.</p><h2>gRPC and GraphQL Client Support</h2><p>The old JSON-RPC client is deprecated. The Sui ecosystem is moving to gRPC and GraphQL, and sui-client-gen is now ready.</p><p>The `.fetch()` method on generated structs now accepts any of:</p><ul><li><p>SuiClient (JSON-RPC, legacy)</p></li><li><p>SuiGrpcClient (gRPC)</p></li><li><p>SuiGraphQLClient (GraphQL)</p></li></ul><pre><code>const pool = await Pool.fetch(grpcClient, poolId);</code></pre><h2>Pre-Formatted Output with dprint</h2><p>Generated TypeScript is now pre-formatted using dprint:</p><ul><li><p>No more running `lint:fix` after generation</p></li><li><p>The `gen/` directory can be excluded from your project&#8217;s linting/formatting</p></li><li><p>Faster CI since there&#8217;s less code to lint</p></li></ul><h2>Migration to move_package_alt</h2><p>Under the hood, sui-client-gen now uses Sui&#8217;s new package manager (`move_package_alt`):</p><p><strong>Simplified model building</strong> - Previously we maintained two separate dependency graphs: one for source packages, one for on-chain packages. The new package manager unifies this.</p><p><strong>Named addresses are package names</strong> - This subtle change is central to dynamic environment switching. Generated code references packages by name rather than hardcoded addresses, enabling runtime address resolution.</p><p><strong>Future-proof</strong> - The old package manager is being phased out. sui-client-gen is ready for what&#8217;s next.</p><h2>publishedAt Overrides</h2><p>Point your SDK at a newly upgraded contract without publishing a new SDK version:</p><pre><code>setActiveEnv(&#8221;mainnet&#8221;, {
  &#8220;my-package&#8221;: &#8220;0xNEW_UPGRADED_ADDRESS&#8221;,
});</code></pre><p>This is particularly useful for wallets (Chrome extensions can&#8217;t update instantly) and any scenario where you need to handle contract upgrades without redeploying your frontend.</p><h2>Getting Started</h2><p>See the repo <a href="https://github.com/kunalabs-io/sui-client-gen/tree/master">https://github.com/kunalabs-io/sui-client-gen/tree/master</a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Sui Prover — A Smart Contract Developer’s Perspective]]></title><description><![CDATA[How formal verification fits into real-world smart contract development]]></description><link>https://blog.kunalabs.io/p/sui-prover-a-smart-contract-developers</link><guid isPermaLink="false">https://blog.kunalabs.io/p/sui-prover-a-smart-contract-developers</guid><dc:creator><![CDATA[Kuna Labs]]></dc:creator><pubDate>Fri, 30 May 2025 19:53:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3f4bd37-d8dd-4d07-8f47-84192e9150d6_400x400.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s been about two and a half years since I wrote my first Move smart contract &#8212; back in November 2022, around the time the first Sui testnet launched. Move was an intriguing language: mysterious yet oddly familiar, which drew me in. There were very few open-source examples of Move code back then, and almost none that could be considered production-ready. The Sui framework was still under heavy development, with breaking changes landing often &#8212; including in the balance and coin modules that we now take for granted. To deepen my understanding of the language, I decided to build a production-worthy implementation of a UniswapV2-style AMM.</p><p>Choosing an AMM was a good call &#8212; not only because I was already familiar with the UniswapV2 math, but also because that AMM model has a certain symmetry and simplicity that makes the implementation elegant if done right. It&#8217;s a great playground to put Move to the test. Plus, UniswapV2 is ubiquitous in DeFi, so I figured it would serve well as an example contract for other developers exploring Move. I finished the implementation and was happy with how it turned out (the code is still up on GitHub: <a href="https://github.com/kunalabs-io/sui-smart-contracts/tree/8eb311b1189cdc8cc1a79a22c5874c40d210bea5/amm">https://github.com/kunalabs-io/sui-smart-contracts/tree/8eb311b1189cdc8cc1a79a22c5874c40d210bea5/amm</a>).</p><p>But as I was writing the unit tests, something kept bugging me. There were certain properties that were hard &#8212; or even impossible &#8212; to fully verify with unit tests alone. These properties had too many edge cases to cover exhaustively, even though they were conceptually straightforward to model.</p><p>Take this property, for example: swapping should never return more value than was input (i.e., the pool can&#8217;t be drained via swaps). This is easy to reason about at a high level, but with unit tests, you can&#8217;t be sure you&#8217;ve covered every possible corner case. If you mess up the formula slightly, the tests might still pass for your inputs, but fail in other cases you didn&#8217;t account for.</p><p>A few more examples:</p><ul><li><p>Zero-input swaps should always output zero.</p></li><li><p>Depositing should never change the asset ratio (price) in the pool.</p></li><li><p>Pool balances should be zero <em>iff</em> LP supply is zero.</p></li></ul><p>Making sure the implementation satisfies these kinds of properties is crucial &#8212; not just to prevent obvious bugs like fund drain, but also to avoid more subtle issues like corrupted state, bricked contracts, rounding errors, unexpected aborts, or broken access control. While unit tests, fuzzing, and audits help a lot, Move also comes with a powerful formal verification tool: the Move Prover. For properties like the ones above, the Prover can be easier to use and give a much higher &#8212; sometimes even absolute &#8212; degree of confidence.</p><p>Back then, the Prover wasn&#8217;t available on Sui, so I shelved the idea and scribbled down my notes for some future time. But the questions stayed with me: <em>Could these properties be formally proven? Could that eliminate some types of tests? Would it make correctness easier to ensure? How hard is it to use the Prover in practice?</em></p><h1>Working with Asymptotic</h1><p>Fast forward to May last year. I was deep into implementing the Kai Leverage smart contracts when Sam reached out to me about Andrei and Cosmin &#8212; static verification experts exploring a smart contract verification startup. They were interested in my AMM implementation and the &#8220;Prover notes&#8221; I&#8217;d written. We jumped on a call and started discussing them.</p><p>Right away, it was clear that proving those properties wouldn&#8217;t be too hard for them. &#8220;There&#8217;s some challenging arithmetic, but it looks doable,&#8221; Andrei said. &#8220;Do you have any other smart contracts?&#8221;</p><p>&#8220;Well,&#8221; I said, &#8220;I&#8217;m working on this leveraged yield farming contract, but it&#8217;s an order of magnitude more complex &#8212; ten times larger, more intricate math, Sui-specific features like dynamic fields, advanced patterns, oracles, external conditions&#8230; It might not be as suitable for formal verification.&#8221;</p><p>But they weren&#8217;t fazed. In fact, they dove into that one instead. I wasn&#8217;t expecting much, but after seeing their initial results, I was convinced: formal verification isn&#8217;t just valuable &#8212; it&#8217;s practical. Not just for auditing finalized contracts, but also during development.</p><h1>Vaults, Rounding Bugs, and Real-World Value</h1><p>I was working on a yield-bearing vault implementation, similar to ERC-4626. It&#8217;s a common DeFi pattern where users deposit tokens and receive shares representing ownership in the vault&#8217;s assets. As the assets grow, the value of those shares increases. You can find the implementation <a href="https://github.com/kunalabs-io/sui-smart-contracts/blob/8eb311b1189cdc8cc1a79a22c5874c40d210bea5/kai/leverage/core/sources/primitives/equity.move">here</a>.</p><p>My main concern wasn&#8217;t the math itself &#8212; it was the rounding errors. Even if you implement the formulas correctly, rounding in the wrong direction can allow the vault to be drained. The language doesn&#8217;t help much here. Robert from OtterSec wrote a great post on this exact issue: <a href="https://osec.io/blog/2024-01-18-rounding-bugs">https://osec.io/blog/2024-01-18-rounding-bugs</a>. The examples he gives are strikingly similar to how things could go wrong in this vault too.</p><p>You can (and should) write unit tests and fuzzing tests to catch this. Fuzzing, in particular, is very applicable here &#8212; it gives you statistical confidence. But it&#8217;s not perfect. As Robert put it: <em>&#8220;I think too many people overindex on how useful the fuzzer mutations are. Throwing a large number of fuzz cycles gives you a very finite increase on the explorable attack surface. If you have a 1/2 trillion chance of hitting a bug, your fuzzer still won&#8217;t hit it&#8230;&#8221;</em></p><p>This is where the Prover shines. Here&#8217;s an actual spec for one of the vault functions:</p><pre><code>#[spec(prove)]
public fun increase_value_and_issue_x64_spec&lt;T&gt;(
    registry: &amp;mut EquityRegistry&lt;T&gt;, value_x64: u128
): EquityShareBalance&lt;T&gt; {
    requires(registry.inv());

    asserts((registry.underlying_value_x64 as u256) + (value_x64 as u256) &lt;= u128::max_value!() as u256);

    let old_registry = old!(registry);

    let result = increase_value_and_issue_x64(registry, value_x64);

    ensures(registry.inv());
    ensures(registry.price_increase(old_registry));
    ensures(result.value_x64 &lt;= value_x64);
    ensures(registry.underlying_value_x64 == old_registry.underlying_value_x64 + value_x64);
    ensures(registry.supply_x64 == old_registry.supply_x64 + result.value_x64);
    ensures(old_registry.supply_x64 &lt;= registry.supply_x64);
    ensures(old_registry.underlying_value_x64 &lt;= registry.underlying_value_x64);

    result
}</code></pre><p>These are powerful assertions. And once you&#8217;re familiar with the Prover, writing specs like this isn&#8217;t harder than writing unit tests. But the results are far stronger: rather than testing specific values or hoping your fuzzer finds issues, the Prover guarantees these properties hold for <em>all</em> possible inputs.</p><p>Once you have specs for low-level modules, you can prove higher-level properties too. Take this function from the Kai Leverage supply pool:</p><pre><code>/// Repays the maximum possible amount of debt shares given the balance.
/// Returns the amount of debt shares and balance repaid.
public(package) fun repay_max_possible&lt;T, ST&gt;(
    pool: &amp;mut SupplyPool&lt;T, ST&gt;, shares: &amp;mut FacilDebtShare&lt;ST&gt;, balance: &amp;mut Balance&lt;T&gt;, clock: &amp;Clock
): (u128, u64) {
    let facil_id = shares.facil_id;
    let balance_by_shares =  calc_repay_by_shares(pool, facil_id, shares.value_x64(), clock);
    let shares_by_balance = calc_repay_by_amount(pool, facil_id, balance.value(), clock);
    
    let (share_amt, balance_amt) = if (balance.value() &gt;= balance_by_shares) {
        (shares.value_x64(), balance_by_shares)
    } else {
        // `shares_by_balance &lt;= shares` here, this can be proven with an SMT solver
        (shares_by_balance, balance.value())
    };
    repay(
        pool,
        shares.split_x64(share_amt),
        balance.split(balance_amt),
        clock
    );

    (share_amt, balance_amt)
}</code></pre><p>Without diving too deep, this function repays the max possible debt using the given balance and debt shares. It&#8217;s part of the liquidation path &#8212; so a bug here could mean positions can&#8217;t be liquidated, which in turn could lead to bad debt.</p><p>I suspected an edge case could cause an abort in <code>shares.split_x64(share_amt)</code>, but couldn&#8217;t be sure. Fuzz testing gave me <em>some</em> confidence, but not a guarantee. I flagged it to Andrei and Cosmin &#8212; and the next day, they had a spec proving it was safe.</p><h1>Why the Prover Matters</h1><p>These examples show that the Prover is not just useful for final verification &#8212; it&#8217;s an asset during development. It can simplify design, replace some types of tests, and give stronger guarantees with comparable effort. Plus, specs are <em>composable</em>: once low-level properties are proven, you can build on them to verify high-level behavior.</p><p>That said, it&#8217;s not a silver bullet. It won&#8217;t replace all tests or audits, especially for economic exploits or protocol-level risks. But it&#8217;s a powerful addition to the toolbox.</p><p>If you&#8217;re curious, check out the specs in the equity, debt, and AMM modules.</p><h1>Looking Ahead</h1><p>Working with Asymptotic convinced me: the Prover has a real place in smart contract development. If adopted widely, it could change the way we build and interact with smart contracts.</p><p>For example, integrating with contracts that have specs is easier. The spec <em>tells you</em> what the function does, and even guarantees it. If it says &#8220;this won&#8217;t abort,&#8221; you don&#8217;t need to code defensively. If it does abort, you know when and why.</p><p>This also ties into reliability. Say a function has a 1% chance of aborting. That&#8217;s tolerable in isolation &#8212; but if your &#8220;10x app&#8221; composes 10 such contracts, your failure rate jumps to 10%. That&#8217;s a problem, especially for backend services or composed protocols.</p><p>We already feel this pain in today&#8217;s apps. For real reliability, we need guarantees &#8212; and the Prover helps us get there.</p><p>Another opportunity: formal verification during audits. Specs can serve as tangible artifacts of what was actually checked. This could raise the bar for audit quality and transparency. Smart contracts with specs should be considered higher quality &#8212; they&#8217;re easier to integrate, more predictable, and safer. Imagine a &#8216;formal verification checkmark&#8217; on explorers and package managers (such as <a href="https://www.moveregistry.com/">moveregistry.com</a>) indicating which contracts have verified specs and to what extent. That could be a real trust signal.</p><h1>Conclusion</h1><p>Audits, while necessary, could become more effective and measurable. Formal specs would serve as concrete artifacts, clearly showing what properties have been verified. This not only increases trust in the auditing process but also offers a practical way to assess the depth of an audit.</p><p>The introduction of formal verification into the CI/CD pipeline could allow us to enforce constraints on dependencies, signaling potential issues before they affect production systems. A &#8216;formal verification checkmark&#8217; on explorers or package managers could give users a clear indication of a smart contract&#8217;s quality and safety. This simple badge would help users trust the contract and contribute to a more secure and reliable ecosystem.</p><p>Static verification can help us achieve a level of reliability and security that current practices alone cannot guarantee. By adopting these methods more widely, we can make decentralized applications safer, more reliable, and easier to integrate &#8212; making blockchain applications more robust and easier to develop. By embracing these practices, we can move towards a more secure and reliable blockchain ecosystem.</p><p>Let&#8217;s build toward that future.</p>]]></content:encoded></item></channel></rss>