<?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[Ramblings of Rigidity]]></title><description><![CDATA[A collection of thoughts about development on Chia.]]></description><link>https://blog.rigidity.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!TrN1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png</url><title>Ramblings of Rigidity</title><link>https://blog.rigidity.dev</link></image><generator>Substack</generator><lastBuildDate>Wed, 08 Apr 2026 20:19:29 GMT</lastBuildDate><atom:link href="https://blog.rigidity.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Brandon Haggstrom]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[brandonhaggstrom@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[brandonhaggstrom@substack.com]]></itunes:email><itunes:name><![CDATA[Brandon Haggstrom]]></itunes:name></itunes:owner><itunes:author><![CDATA[Brandon Haggstrom]]></itunes:author><googleplay:owner><![CDATA[brandonhaggstrom@substack.com]]></googleplay:owner><googleplay:email><![CDATA[brandonhaggstrom@substack.com]]></googleplay:email><googleplay:author><![CDATA[Brandon Haggstrom]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Rue: It's Alive!]]></title><description><![CDATA[I&#8217;m excited to announce that the latest iteration of Rue Lang is now released into the wild.]]></description><link>https://blog.rigidity.dev/p/rue-its-alive</link><guid isPermaLink="false">https://blog.rigidity.dev/p/rue-its-alive</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Sun, 05 Oct 2025 03:35:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TrN1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;m excited to announce that the latest iteration of Rue Lang is now released into the wild. It&#8217;s been quite the bumpy road to get here, but it&#8217;s finally ready!</p><p>You can learn more about the language itself or how to install it on the <a href="https://rue-lang.com/">Rue documentation</a>. There&#8217;s also a <a href="https://play.rue-lang.com/">playground website</a> where you can try some examples right in your browser.</p><h2>What is Rue?</h2><p>Around 3 years ago when I was getting into <a href="https://chialisp.com/">Chialisp</a>, I yearned for an alternative that was more similar to modern programming languages I was used to (such as TypeScript, or more recently Rust). The strange Lisp syntax and lack of typing was frustrating to me and was harder to mentally model (though I&#8217;ve gotten more used to it by now). And usually when I get frustrated about things, I take it into my own hands to do something about it rather than complain.</p><p>So around the same time I initially started working on Rue Lang, a new programming language that compiles to <a href="https://chialisp.com/clvm/">CLVM</a>. I actually had a fair bit of experience writing recursive descent parsers prior to working on Chia, so that part was natural to me. And I&#8217;d always been interested in programming language design, but never was able to write anything other than simple interpreters before.</p><p>Since I had to juggle Rue with my full time job at <a href="https://www.chia.net/">Chia Network Inc</a> and other projects such as <a href="https://sagewallet.net/">Sage Wallet</a>, progress was slow (especially when I was procrastinating on hard to solve design challenges or compiler bugs). The compiler went through several complete rewrites from scratch due to large scale architectural issues that I learned from along the way.</p><p>However, I&#8217;ve recently had some time to work on the latest version of the compiler and I&#8217;ve gotten it across the finish line (at least for an initial release). I&#8217;m sure it won&#8217;t be perfect, but just like when I initially launched Sage, it marks a point of no return so to speak.</p><h2>What is Rue solving?</h2><p>One of the most common things I hear from people who are interested in developing on Chia is that it&#8217;s difficult to understand Chialisp. I believe that Rue will allow people to get past some of their initial hesitation to get involved, and focus more on the <a href="https://docs.chia.net/chia-blockchain/coin-set-model/intro/">Coin Set Model</a> rather than the language itself while learning. This combined with improved tooling will create a better developer experience for beginners.</p><p>Additionally, there&#8217;s an opportunity to add new compiler optimizations that reduce the size of the CLVM byte code for puzzles. The results are already promising, and there is room to improve. New versions of the compiler can introduce additional optimizations without breaking puzzles that still use older compiler versions.</p><p>And finally, as we start to introduce more complicated decentralized applications on the Chia blockchain, having a more capable compiler will become more important. Being able to easily audit the code, leverage powerful <a href="https://microsoft.github.io/language-server-protocol/">language server protocol</a> features, and efficiently write many puzzles with the same codebase will increase productivity and safety.</p><h2>What&#8217;s the catch?</h2><p>Rue is very new, and should be considered on the &#8220;bleeding edge&#8221; at the moment. While its test suite aims to regression test common edge cases and many full example puzzles, there is bound to be bugs as with any new software. Chialisp on the other hand, has had years to be battle tested by many primitives that are deployed in production.</p><p>The plan is to incrementally roll out some puzzles using Rue on-chain, and to ensure everything is working as intended:</p><ol><li><p>They will be fully tested in both the Rue compiler codebase and the driver code to ensure the puzzles work as intended</p></li><li><p>New tests will be continually added in the compiler to build confidence</p></li><li><p>CLVM byte code for these puzzles will also be manually inspected before deployment to ensure nothing was overlooked</p></li></ol><p>You can never be too careful.</p><h2>What&#8217;s next?</h2><p>I will keep iterating on the Rue compiler, and roll out new features such as:</p><ol><li><p>Editor completions</p></li><li><p>Goto definition</p></li><li><p>Type information on hover</p></li><li><p>Importing multiple files (modules)</p></li></ol><p>Please feel free to give Rue a try and let me know if you have any feedback on the <a href="https://discord.gg/sagewallet">Sage Wallet Discord</a>!</p>]]></content:encoded></item><item><title><![CDATA[Optimizing Chia Puzzles]]></title><description><![CDATA[And the changes made to the Rue compiler to make this possible]]></description><link>https://blog.rigidity.dev/p/optimizing-chia-puzzles</link><guid isPermaLink="false">https://blog.rigidity.dev/p/optimizing-chia-puzzles</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Tue, 30 Sep 2025 22:42:48 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/edd5ec38-54c0-444a-8e15-a40223890259_780x440.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>All Chia puzzles (for example the NFT state layer, NFT ownership layer, and CAT2 puzzle) are compiled to CLVM before being used on-chain. It&#8217;s important to make sure that these puzzles are as optimized as possible to maximize the throughput of transactions. Let&#8217;s look into some of the optimizations in the Rue compiler, and how they compare to Chialisp.</p><h2>CLVM Cost</h2><p>The cost of a coin spend is measured by a unit called &#8220;cost&#8221;. This doesn&#8217;t necessarily directly correlate to XCH paid as a transaction fee, however they are related.</p><p>The following things have a CLVM cost:</p><ol><li><p>12,000 per byte stored in the blockchain database for a program</p></li><li><p>1,200,000 per <a href="https://chialisp.com/conditions/#agg-sig-me">AGG_SIG</a> condition</p></li><li><p>1,800,000 per CREATE_COIN condition</p></li><li><p>Various costs for allocating memory and using operators at runtime</p></li></ol><p>The thing that tends to add up the most dramatically is the 12,000 cost per byte. So, this is what Chia puzzle developers and the compiler optimize the most heavily.</p><p>There is a maximum of 11,000,000,000 (11 billion) cost per block. If your program uses 11,000,000 (11 million) cost, you can spend 1,000 of them per block. Thus, there&#8217;s a direct relationship between cost and throughput.</p><p>The mempool allows for transactions that are at most half the size of a block, and a total space of approximately 10 times the size of a block. There isn&#8217;t a minimum fee unless the mempool is full, but transactions are prioritized for block inclusion based on the highest fee per cost ratio.</p><p>You can read more about the mempool on the <a href="https://docs.chia.net/chia-blockchain/architecture/mempool/">official Chia docs</a>.</p><h2>Constant Folding</h2><p>The simplest of optimizations is <a href="https://en.wikipedia.org/wiki/Constant_folding">constant folding</a>, wherein you simplify expressions at compile time. This isn&#8217;t particularly interesting, but it allows for nested calls to <em>concat</em>, <em>sha256</em>, and various operators to be simplified as much as possible to reduce the amount of bytes requires to express the intended value.</p><p>Importantly, the Chialisp compiler decides to interpret calls to <em>sha256</em> with known values and insert the resulting hash instead of the call to the operator. This results in 32 bytes (approximately 384,000 CLVM cost) being added to the program, which is in most cases quite inefficient. Rue instead elects to preserve the operator call unless you explicitly use <em>sha256_inline</em>.</p><h2>Let Bindings</h2><p>Because classic Chialisp doesn&#8217;t have a way to declare and reuse bindings, it&#8217;s common to see code like this:</p><pre><code>(mod (first second)
    (defun stager (first second computed_third computed_fourth)
        ...
    )

    (stager first second (+ first second) (- second first))
)</code></pre><p>This is essentially achieving the same thing - you are calculating a value, and binding it to a parameter in a function. However, notice that <em>first</em> and <em>second</em> are being passed around unchanged - you have to manually pass values in from one function to the next just to prevent reuse of calculated values. This adds unnecessary runtime and byte cost in the construction of the parameters to <em>stager</em>.</p><p>In Rue, you can simply declare bindings like so:</p><pre><code>fn main(first: Int, second: Int) -&gt; Int {
    let computed_third = first + second;
    let computed_fourth = second - first;
    ...
}</code></pre><p>This is both more readable, and more efficient. Instead of passing the individual values through to another function, it will group the bindings and prepend them to the rest of the environment. This can sometimes result in a bit larger CLVM paths (which are how references to values in the environment work), but it&#8217;s more efficient both in terms of runtime cost and byte cost, so it&#8217;s well worth it.</p><h2>Binary Trees</h2><p>All credit for the idea of this optimization goes to <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;yakuhito&quot;,&quot;id&quot;:69620055,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf6a370-abec-45df-8727-c362821920ee_400x400.jpeg&quot;,&quot;uuid&quot;:&quot;1886dcdd-4e58-4d05-a68f-17e2550ef612&quot;}" data-component-name="MentionToDOM"></span> (<a href="https://x.com/yakuh1t0">Twitter</a>).</p><p>In CLVM, the environment to a program is a binary tree. However, we often use it as a glorified list - both for function calls, and things like captures and bindings. This throws away a lot of the cost savings you could get from organizing things in a tree structure.</p><p>As a simple example, as far as I can tell it&#8217;s not even possible in Chialisp to use the dot operator at the end of the argument list of a function to indicate that you don&#8217;t want it to be nil terminated. This adds an additional call to the cons operator for every function call, and increases the CLVM paths unnecessarily. Rue has the spread operator to allow you to do this without needing to write CLVM directly.</p><p>However, as a result of a discussion with <span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;yakuhito&quot;,&quot;id&quot;:69620055,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf6a370-abec-45df-8727-c362821920ee_400x400.jpeg&quot;,&quot;uuid&quot;:&quot;32ffe16f-8cd1-4bd2-a0b8-5a7c1a253d26&quot;}" data-component-name="MentionToDOM"></span>, we figured out how this could be optimized further. Instead of simply prepending binding groups to the environment, you can organize the symbols into an optimized binary tree (more frequently used symbols come first) and cons it with the rest of the environment.</p><p>This provided some cost savings, but after generalizing it to function captures and function parameters, the costs of Rue programs went dramatically down. Every single function call, including functions defined in the standard library such as <em>tree_hash</em>, requires less bytes to include in the generated CLVM and has a lower runtime cost.</p><p>The caveat with this optimization is that functions which are converted into values (closures) lose symbol information, and the compiler can&#8217;t figure out how to organize the binary tree anymore (or if it even should). Thus, this optimization is disabled for all function values (ie if you don&#8217;t call a function directly by its name). Additionally, there will be an <em>extern</em> keyword which can be used to disable this functionality.</p><p>The main function could benefit from this optimization as well, but it&#8217;s currently disabled to preserve the layout of the solution for now. This will likely be configurable in the future.</p><h2>Verification Statements</h2><p>In CLVM, there are four similar operators called <em>bls_pairing_identity</em>, <em>bls_verify</em>, <em>secp256k1_verify</em>, and <em>secp256r1_verify</em>. These take in a list of arguments (which can&#8217;t be determined at runtime currently) and either return nil if the verification is successful, or raise an error if not. I call these, and any function with a similar pattern, a &#8220;verification statement&#8221;, since the return value is meaningless.</p><p>In Chialisp, you would have to awkwardly figure out where to put these in your program, since the return value will be nil. This often means manually constructing lists and inserting these verification opcodes in the place of the nil terminator. In Rue, this is done for you so you don&#8217;t have to think about it.</p><p>If you use an expression as a statement (ending it with a semicolon), the compiler will include it in the generated CLVM in the best way it can, with a few optimizations to improve on CLVM cost.</p><p>Firstly, if there are enough instances of nil in the current scope of the generated LIR, it will insert each verification statement in place of one of them. Otherwise, or if any of the verification statements may return a non-nil value according to the type system, it will insert all of them in an <em>all</em> operator in the first nil slot. And finally, if there were no nil values to substitute, it will wrap the rest of the expression in a cons pair, insert the verifications as the first value, and then unwrap the rest value. This has the effect of running the verification statements while discarding the value (which means any assertions will raise an error if they fail as expected).</p><h2>The Results</h2><p>I&#8217;ve been experimenting with porting common Chialisp puzzles to Rue, both to test the compiler&#8217;s correctness as I make changes, and to incrementally optimize the generated CLVM.</p><p>Here are a few of the latest comparisons of the number of bytes (less than 100% is better):</p><ol><li><p>CAT2 is 93.5% of the size</p></li><li><p>Partial offers are 95.9% of the size</p></li><li><p>Royalty split is 101% of the size (more work to be done here)</p></li></ol><p>For the CAT example, this could mean that if you were to spend 100 CAT coins in Chialisp, you could instead spend 107 in Rue with the same CLVM cost.</p><h2>Conclusion</h2><p>When designing Rue, my main concern was that puzzles written in it wouldn&#8217;t be efficient enough to be used in production, and nobody would adopt the language (even if the syntax and type system were nice to use) as a result of this. However, I&#8217;ve been pleasantly surprised by the optimizations I&#8217;ve been able to implement into the compiler to bring it close to, and in many cases exceed, the Chialisp compiler.</p><p>I&#8217;ll keep working on optimizing the language (even after the first release is out). But, it&#8217;s also important to write more and more unit tests to ensure program correctness isn&#8217;t left behind in the pursuit of efficiency. Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Building the Rue Type System]]></title><description><![CDATA[This post goes into detail on how the type system of the Rue programming language works and the rationale behind its design.]]></description><link>https://blog.rigidity.dev/p/building-the-rue-type-system</link><guid isPermaLink="false">https://blog.rigidity.dev/p/building-the-rue-type-system</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Wed, 24 Sep 2025 03:59:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TrN1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This post goes into detail on how the type system of the Rue programming language works and the rationale behind its design. If you need a refresher, this is a link to the previous blog post where I described what Rue Lang is and what sets it apart from <a href="https://chialisp.com/">Chialisp</a>:</p><div class="embedded-post-wrap" data-attrs="{&quot;id&quot;:171108259,&quot;url&quot;:&quot;https://blog.rigidity.dev/p/rue-and-improved&quot;,&quot;publication_id&quot;:3538373,&quot;publication_name&quot;:&quot;Ramblings of Rigidity&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!TrN1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png&quot;,&quot;title&quot;:&quot;Rue and Improved&quot;,&quot;truncated_body_text&quot;:&quot;Rue Lang is a new programming language I&#8217;ve been working on for quite a while. It&#8217;s based on Rust, and aims to provide an alternative to Chialisp for writing puzzles for smart coins on the Chia blockchain.&quot;,&quot;date&quot;:&quot;2025-08-16T16:47:31.733Z&quot;,&quot;like_count&quot;:1,&quot;comment_count&quot;:0,&quot;bylines&quot;:[{&quot;id&quot;:176681691,&quot;name&quot;:&quot;Brandon Haggstrom&quot;,&quot;handle&quot;:&quot;rigidity&quot;,&quot;previous_name&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png&quot;,&quot;bio&quot;:&quot;Software engineer at Chia Network Inc, and Chia ecosystem developer with a passion for Rust.&quot;,&quot;profile_set_up_at&quot;:&quot;2024-12-17T04:53:56.398Z&quot;,&quot;reader_installed_at&quot;:null,&quot;publicationUsers&quot;:[{&quot;id&quot;:3607277,&quot;user_id&quot;:176681691,&quot;publication_id&quot;:3538317,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:true,&quot;publication&quot;:{&quot;id&quot;:3538317,&quot;name&quot;:&quot;Brandon Haggstrom&quot;,&quot;subdomain&quot;:&quot;rigidity&quot;,&quot;custom_domain&quot;:null,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;Software engineer at Chia Network Inc, and Chia ecosystem developer with a passion for Rust.&quot;,&quot;logo_url&quot;:null,&quot;author_id&quot;:176681691,&quot;primary_user_id&quot;:176681691,&quot;theme_var_background_pop&quot;:&quot;#FF6719&quot;,&quot;created_at&quot;:&quot;2024-12-17T04:55:50.905Z&quot;,&quot;email_from_name&quot;:null,&quot;copyright&quot;:&quot;Brandon Haggstrom&quot;,&quot;founding_plan_name&quot;:null,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;disabled&quot;,&quot;language&quot;:null,&quot;explicit&quot;:false,&quot;homepage_type&quot;:&quot;profile&quot;,&quot;is_personal_mode&quot;:true}},{&quot;id&quot;:3607334,&quot;user_id&quot;:176681691,&quot;publication_id&quot;:3538373,&quot;role&quot;:&quot;admin&quot;,&quot;public&quot;:true,&quot;is_primary&quot;:false,&quot;publication&quot;:{&quot;id&quot;:3538373,&quot;name&quot;:&quot;Ramblings of Rigidity&quot;,&quot;subdomain&quot;:&quot;brandonhaggstrom&quot;,&quot;custom_domain&quot;:&quot;blog.rigidity.dev&quot;,&quot;custom_domain_optional&quot;:false,&quot;hero_text&quot;:&quot;A collection of thoughts about development on Chia.&quot;,&quot;logo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png&quot;,&quot;author_id&quot;:176681691,&quot;primary_user_id&quot;:null,&quot;theme_var_background_pop&quot;:&quot;#FF6719&quot;,&quot;created_at&quot;:&quot;2024-12-17T05:11:55.824Z&quot;,&quot;email_from_name&quot;:&quot;Brandon Haggstrom&quot;,&quot;copyright&quot;:&quot;Brandon Haggstrom&quot;,&quot;founding_plan_name&quot;:null,&quot;community_enabled&quot;:true,&quot;invite_only&quot;:false,&quot;payments_state&quot;:&quot;disabled&quot;,&quot;language&quot;:null,&quot;explicit&quot;:false,&quot;homepage_type&quot;:&quot;newspaper&quot;,&quot;is_personal_mode&quot;:false}}],&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null,&quot;status&quot;:{&quot;bestsellerTier&quot;:null,&quot;subscriberTier&quot;:null,&quot;leaderboard&quot;:null,&quot;vip&quot;:false,&quot;badge&quot;:null}}],&quot;utm_campaign&quot;:null,&quot;belowTheFold&quot;:false,&quot;type&quot;:&quot;newsletter&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPostToDOM"><a class="embedded-post" native="true" href="https://blog.rigidity.dev/p/rue-and-improved?utm_source=substack&amp;utm_campaign=post_embed&amp;utm_medium=web"><div class="embedded-post-header"><img class="embedded-post-publication-logo" src="https://substackcdn.com/image/fetch/$s_!TrN1!,w_56,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png"><span class="embedded-post-publication-name">Ramblings of Rigidity</span></div><div class="embedded-post-title-wrapper"><div class="embedded-post-title">Rue and Improved</div></div><div class="embedded-post-body">Rue Lang is a new programming language I&#8217;ve been working on for quite a while. It&#8217;s based on Rust, and aims to provide an alternative to Chialisp for writing puzzles for smart coins on the Chia blockchain&#8230;</div><div class="embedded-post-cta-wrapper"><span class="embedded-post-cta">Read more</span></div><div class="embedded-post-meta">8 months ago &#183; 1 like &#183; Brandon Haggstrom</div></a></div><h2>Type Systems</h2><p>It&#8217;s important to first understand what the goal of a type system is. The <a href="https://en.wikipedia.org/wiki/Type_system">Wikipedia article</a> goes into a lot of detail, but essentially it boils down to preventing compilation of programs that use data in the wrong way. For example, if you try to assign an integer to a function that expects a boolean, it will fail to compile. This prevents a large array of logic errors that could lead a program to either crash or have an unintended result.</p><p>Many languages employ dynamic type checking, wherein the values have type information associated with them at runtime. While interpreting the program, the runtime will check the type and raise an error if there is a mismatch. However, static type checking enforces these checks at compile time, before the program is ever run. This can be useful for catching bugs earlier on, improving maintainability, and optimizing compiled programs.</p><p>For these reasons, and because it makes code easier to audit, Rue is a strictly typed programming language. Types are required for all values, whether they are inferred or explicitly specified. Bypassing the type checker or overriding the type of a value is intentionally cumbersome to discourage doing so, since it reduces the safety of the program.</p><p>However, making a language statically typed will be frustrating unless the type system is powerful enough to sufficiently express the intention of complex programs with types. Every time the compiler isn&#8217;t smart enough to understand what you&#8217;re trying to do, and gives you a type error that you know is unnecessary, it takes you out of the flow of writing code and forces you to find workarounds.</p><h2>CLVM Types</h2><p>There are only two fundamental types in <a href="https://chialisp.com/clvm/">CLVM</a> (the bytecode that Rue compiles down into):</p><ol><li><p><em>Atom</em> - an arbitrary sequence of bytes</p></li><li><p><em>Pair</em> - two values (each of which can either be an atom or pair)</p></li></ol><p>Thus, the first two Rue types are born: <em>Atom</em> and <em>(A, B)</em>.</p><p>You can nest these types:</p><pre><code><code>(Atom, (Atom, Atom))</code></code></pre><h2>Atoms</h2><p>Often atoms have specific semantics or constraints that you&#8217;d like to encode in the type system.</p><p>There are various subtypes that are provided:</p><ol><li><p><em>Bytes</em> - a sequence of bytes</p></li><li><p><em>Bytes32</em> - a sequence of exactly 32 bytes (useful for <a href="https://en.wikipedia.org/wiki/SHA-2">SHA-256</a> hashes)</p></li><li><p><em>PublicKey</em> - a <a href="https://en.wikipedia.org/wiki/BLS_digital_signature">BLS-12381</a> public key</p></li><li><p><em>Int</em> - an arbitrary precision signed integer</p></li><li><p><em>Bool</em> - a union of <em>true</em> or <em>false</em></p></li><li><p><em>nil</em> - an empty atom</p></li></ol><p>As seen with booleans and nil, it&#8217;s possible to use specific values as types. For example, you can use <em>42</em> as a type that represents that value. Anything else, be it an arbitrary int or a different value, will not be assignable to that type.</p><h2>Unions</h2><p>Now that you can get specific about whether a type is an atom, a pair, or a specific value, it&#8217;s important to be able to represent union types. A union represents more than one type - where <em>A | B</em> means it matches either A or B.</p><h2>Type Aliases</h2><p>A type alias is like a variable for types. It lets you hide the complexity behind a reusable name.</p><pre><code><code>type Owner = PublicKey | nil;</code></code></pre><p>This can also be used to create <a href="https://en.wikipedia.org/wiki/Recursive_data_type">recursive data types</a> (the Wikipedia article linked actually represents the equivalent of the following example in Lisp):</p><pre><code><code>type List&lt;T&gt; = nil | (T, List&lt;T&gt;);</code></code></pre><p>This means that a list can either be <em>nil</em>, or one element followed by zero or more other elements (another <em>List</em>). Even though <em>List</em> is a built-in type in the language, this is the exact way that it&#8217;s implemented (and you can write the type yourself if you wanted to).</p><p>Recursive types were the biggest challenge to implement in the type system. Every operation that interacts with types, including comparison, type checking, subtraction, and replacement, must account for the fact that you might end up infinitely checking the same type over and over. Solutions in the Rue compiler include maximum recursion depths, a stack of &#8220;visited&#8221; comparisons, and a cache of references to results that are yet to be determined. I&#8217;m very excited that I was able to preserve such a powerful aspect of the type system and fight through all of the problems I faced when designing it.</p><p>Another example of a recursive type is <em>Any</em> (which represents, well, any CLVM value):</p><pre><code><code>type Any = Atom | (Any, Any);</code></code></pre><h2>Structs</h2><p>Now that you can represent any CLVM structure in Rue, it&#8217;s important to be able to name the fields in a list.</p><p>This is where structs come in:</p><pre><code><code>struct Coin {
  parent_coin_id: Bytes32,
  puzzle_hash: Bytes32,
  amount: Int,
}</code></code></pre><p>This type has the same structure as <em>(Bytes32, (Bytes32, (Int, nil)))</em>, but it allows you to reference the fields by name (such as <em>coin.amount</em>).</p><p>Structs also have the unique property that they are semantically different from one another. If you define two identical structs named <em>Coin1</em> and <em>Coin2</em>, you cannot assign from one to the other (even though they have the same <em>structure</em>), unless you cast them explicitly using the <em>as</em> operator.</p><p>A struct can have default values, which makes it easier to define types such as conditions:</p><pre><code><code>struct ReserveFee {
  opcode = 52,
  amount: Int,
}</code></code></pre><p>Now you can construct this with <em>ReserveFee { amount: 42 }</em> rather than needing to specify the opcode as well.</p><h2>Type Guards</h2><p>Well, now we have a bunch of types that we can use to represent the structure and semantics of CLVM values accurately. But we&#8217;re missing a way to check what type a value is at runtime. This is where type guards come in.</p><p>A type guard is a combination of two things:</p><ol><li><p>Type check - which generates code that checks the type of a value at runtime</p></li><li><p>Type replacement - which modifies the type of a symbol or field at compile time</p></li></ol><p>As a concise example:</p><pre><code><code>fn count(list: List&lt;Int&gt;) -&gt; Int {
  // We&#8217;ve reached the end of the list, so there&#8217;s no length.
  if list is nil {
    return 0;
  }

  // Now we know that list is (Int, List&lt;Int&gt;) rather than nil
  1 + count(list.rest)
}</code></code></pre><p>When you use the expression <em>list is nil</em> you are creating a type guard - it will output the CLVM <em>(not (l list))</em>, which checks that the value is an atom (nil in this case). Inside of the if branch, the type of <em>list</em> is <em>nil</em>. However, on the outside, the type is <em>(Int, List&lt;T&gt;)</em> thanks to subtraction! This means that we&#8217;ve narrowed the type down by checking the value at runtime.</p><p>This feature is the most important aspect of the type system, and also what took the most effort to get right. It&#8217;s optimized such that it won&#8217;t output unnecessary checks (if the value can never be a type, there&#8217;s no point in checking for it).</p><h3>Subtraction</h3><p>Subtraction is instrumental in making sure that inverting a type guard for else branches works.</p><p>Fundamentally, these are the steps to implement subtraction:</p><ol><li><p>Recursively extract the original type into a list of union variants (along with their corresponding semantic types, if any)</p></li><li><p>Remove any union variants that are assignable to the right hand side</p></li><li><p>Repackage and group the union variants into their corresponding semantic types</p></li></ol><p>Essentially this means that any types that were a subset of the if branch are filtered out of the else branch (which matches the behavior at runtime).</p><h3>Replacement</h3><p>Type guarding doesn&#8217;t just work on entire symbols - if you check the type of a field in a symbol whose type is a struct, the symbol&#8217;s type will be replaced with one wherein that field is subtracted in the else branch.</p><p>This involves recursively walking the tree of pairs and substituting based on the path of the field that you type guarded. If there are multiple type guards on separate fields, they will be aggregated together in the final type when referenced later on in the branch.</p><h2>Function Types</h2><p>Function types are a bit special - technically a function <em>could</em> be any CLVM value, but not every CLVM value could be a function. And there&#8217;s really no way to determine whether a value is a certain function type at compile time. Thus, it&#8217;s possible to type guard on a function type, but not check whether a value is a function.</p><p>Although, a function type is always assignable to itself or any function type with a superset of its argument and return types.</p><h2>Conclusion</h2><p>We can build fully functional Chia puzzles by putting all these pieces together (pun intended). The hope is that you get the same level of flexibility that Chialisp provides, with the benefits of static typing at compile time.</p><p>In future blog posts, I&#8217;ll cover how the dependency graph, HIR lowerer, and optimizer work. In the meantime, I&#8217;ll keep working on the compiler, and getting it closer to a new alpha release. The rewrite has been quite the project, but it&#8217;s nearing initial completion.</p><p>Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Rue and Improved]]></title><description><![CDATA[The puns will continue until morale impRUEves]]></description><link>https://blog.rigidity.dev/p/rue-and-improved</link><guid isPermaLink="false">https://blog.rigidity.dev/p/rue-and-improved</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Sat, 16 Aug 2025 16:47:31 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0beb501c-281e-40ea-96f5-53f1559aef20_1728x688.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Rue Lang is a new programming language I&#8217;ve been working on for quite a while. It&#8217;s based on Rust, and aims to provide an alternative to Chialisp for writing puzzles for smart coins on the Chia blockchain.</p><p>When I first started working on Rue a couple years ago, I knew it would be a time consuming project. But what I didn&#8217;t prepare for was the sheer amount of time I&#8217;d spend writing and rewriting the same code over and over again. I&#8217;ve come about as close as you can get to going insane without actually going insane (at least, not yet).</p><p>So was it worth it? Well, I&#8217;ll let you be the judge of that.</p><h2>What is Chialisp?</h2><p>It&#8217;s important to start with where we are today. All puzzles on the Chia blockchain are currently written using a language named <a href="http://chialisp.com/">Chialisp</a>. It is, as the name suggests, based on <a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a>.</p><p>Chialisp is pure - given the same input, a program will <em>always</em> provide the same output. Programs do not rely on any external state, and in fact are themselves stateless (there are no variables that can be mutated).</p><p>It&#8217;s also a functional language, which means that functions aren&#8217;t given special treatment and are just values that can be passed around like any other. The combination of these two traits makes it straightforward to audit the logic of the program if you can understand the syntax.</p><h2>What is CLVM?</h2><p><a href="https://chialisp.com/clvm">CLVM</a> (the Chialisp Virtual Machine) is a low level bytecode language. You can think of it like the Chia equivalent of assembly language, or similar to the EVM on Ethereum. The bytecode gets executed on a fully sandboxed virtual machine when you spend a coin.</p><p>Every value in CLVM is either a pair of two values or an atom (a sequence of bytes). This is enough to represent anything, including lists and operators. However, these constructs are extremely low level and hard to read without having access to the pre-compilation source code. Additionally, the number of available operators is quite limited compared to what you may expect.</p><p>The idea is that Chialisp compiles down <em>into</em> CLVM, rather than us writing the CLVM bytecode itself. However, Chialisp is missing several abstractions we come to expect from programming languages:</p><ol><li><p>It does not support <a href="https://en.wikipedia.org/wiki/Scope_(computer_science)">lexical scoping</a>, where you can declare bindings in multiple nested scopes and reference them from anywhere within. You can only reference constants or parameters of the current function (not parameters of the outer module).</p></li><li><p>It does not have a type checker. All values are either a pair or an atom (like in CLVM) and there&#8217;s no way to enforce at compile time that the correct value is passed into a function.</p></li><li><p>There&#8217;s no standard library, aside from a few helper macros like <em>list</em> and <em>if</em>.</p></li><li><p>Classic Chialisp lacks the ability to declare variable bindings, though the less commonly used modern compiler does support them.</p></li><li><p>The syntax is often hard to understand and is missing niceties like statements. This reduces readability, and therefore auditability.</p></li></ol><p>And thus we end up writing a lot of CLVM opcodes directly in our Chialisp programs, which defeats much of the point of a higher level language.</p><h2>Introducing Rue</h2><p>Rue is a high level programming language that compiles to CLVM just like Chialisp does. The compiler might sound like a simple translation between Rue and CLVM. But that couldn&#8217;t be further from the truth. Instead, it requires several stages to convert the syntax into something that can be interpreted by the CLVM runtime.</p><h3>Lexer</h3><p>The lexer is responsible for breaking the source code into small pieces called &#8220;tokens&#8221;. The reason for doing this is primarily to make it easier to parse one token at a time efficiently rather than needing to backtrack when you reach a character you don&#8217;t expect. It also improves the parser&#8217;s error messages considerably.</p><p>This means turning code like this:</p><pre><code>3 + 2</code></pre><p>Into the following tokens: <em>Int</em>, <em>Whitespace</em>, <em>Int</em></p><h3>Parser</h3><p>Once we&#8217;ve produced a list of tokens, the parser will convert these into &#8220;parse tokens&#8221;, which are slightly simplified versions of the lexer tokens. Things like missing end quotes are turned into parser errors at this stage.</p><p>Then, a hand written grammar is applied to the parse tokens recursively to convert them into a lossless parse tree. All whitespace is preserved in the document, to make it possible to reconstruct the source code later (which is useful for language servers and formatters, for example).</p><p>Instead of a linear list of tokens, we now have a tree of syntax nodes for language constructs like functions, statements, and expressions.</p><h3>AST</h3><p>The parse tree is useful, but it&#8217;s loosely typed and lacking concrete structure. It&#8217;s possible for subtrees to be missing due to parsing errors. We need an abstraction on top of it that provides a simpler interface to work with for the compiler.</p><p>This is where the Abstract Syntax Tree (AST) comes in. We can lazily walk the parse tree and find relevant nodes, using AST types with methods such as <code>expr()</code> and <code>args()</code>.</p><p>Thankfully it&#8217;s pretty easy to convert from the parse tree to the AST, since they&#8217;re both in a tree structure. This is the final step before the actual compilation happens.</p><h3>HIR</h3><p>The next step is to compile from the AST to the HIR (high-level intermediate representation). This is when the bulk of the work of the compiler happens:</p><ol><li><p>We declare types</p></li><li><p>We declare symbols that can reference declared types</p></li><li><p>We compile types that can reference other types</p></li><li><p>We compile symbols and check the resolved types</p></li><li><p>We compile expressions into HIR nodes</p></li></ol><p>It&#8217;s done in this order to ensure that the order of items (functions and constants) in the program doesn&#8217;t matter. You can reference an item from another regardless of the order (even recursively) as long as they&#8217;re both in scope. However, because of this, every item must have a well defined return type and can&#8217;t rely on inference (because the body might not have been resolved by the time the type is needed).</p><p>The type system is still a work in progress, so I won&#8217;t dive too much into it. But it contains types like Bytes, Bytes32, Int, and so on. Everything must be either explicitly typed or have the type inferred from its value. This reduces the number of runtime errors you run into while debugging programs written in Rue.</p><h3>LIR</h3><p>There used to be a MIR phase between the HIR and LIR, but that was removed for simplicity. The LIR (low-level intermediate representation) is a single step above CLVM and represents all of the operators that you can compile code into. There aren&#8217;t many abstractions at this level and it&#8217;s perfect for performing final optimizations before generating the final CLVM bytecode.</p><p>The most challenging aspect of converting between the HIR and LIR is the environment. Rue has a concept of lexical scoping, if statements, and immutable variable bindings. On the other hand, CLVM only understands the &#8220;environment&#8221;, which is a non-hierarchical tree of values that are available to the program contained within.</p><p>If you want to add a binding to the environment, you have to effectively <a href="https://en.wikipedia.org/wiki/Partial_application">curry</a> it into the rest of the program. This means taking the program (which is a function) and creating a new one with some of its arguments pre-applied. However, when you do this, you have to also shift to the right the environment path for all other symbols referenced inside the program (since the new symbols are inserted on the left).</p><p>An if statement or assert statement gets translated into an if expression with the rest of the program as one of its branches. These constructs are just <a href="https://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a> for expressions.</p><p>When you lower a function into the LIR, you need to make sure that any symbols it references that are in an enclosing scope (captures) get explicitly passed in when the function is called. Additionally, if you try to use a function as a value, it must first be turned into a closure that has its captured arguments curried in at runtime.</p><p>This translation step is the hardest to get right, and now that I&#8217;ve figured it out I don&#8217;t plan on touching it more than I have to (since it works). The last time I built the Rue compiler, this roadblock was the reason I stopped working on it for about 8 months. The HIR =&gt; MIR conversion I had at the time was fundamentally broken and I didn&#8217;t know how to fix it.</p><h2>So what now?</h2><p>Now that I&#8217;ve solved the HIR =&gt; LIR conversion process, I can focus on the type system and adding language features like I was before. This is the exciting part since I have a clear picture of how the language should work (it will be slightly different than previous designs).</p><p>I expect to have a usable and well tested implementation of the Rue compiler in the coming month(s). Until then, stay tuned!</p>]]></content:encoded></item><item><title><![CDATA[What's new with Sage]]></title><description><![CDATA[And what to expect in the future]]></description><link>https://blog.rigidity.dev/p/whats-new-with-sage</link><guid isPermaLink="false">https://blog.rigidity.dev/p/whats-new-with-sage</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Sat, 02 Aug 2025 18:39:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/S6bxdGIA9oQ" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A new Sage release is out, but it&#8217;s been a while since the last one so I figured I should explain what&#8217;s been worked on over the past couple months. You may be surprised to hear that over 25,000 lines of code (which is roughly 50% of the codebase at the time of writing this) have been affected between the last version and now!</p><p>I want to give a huge thanks to <a href="https://github.com/dkackman">Don Kackman</a> for all of the help with the project and for making it possible to get this release across the finish line.</p><p>You can download binaries for MacOS, Windows, and Linux on <a href="https://github.com/xch-dev/sage/releases/tag/v0.11.0">GitHub</a> or download the app for desktop, Android, or iOS on the <a href="https://sagewallet.net/">Sage website</a> (although the mobile versions need to go through their respective approval processes first).</p><p>The biggest two changes are architectural, but a lot of features and bug fixes have been slipped in along the way.</p><h2>Action System</h2><p>We&#8217;ve fully transitioned from manually constructing transactions to using the new Action System introduced in the Wallet SDK. The action system (not to be confused with Yakuhito&#8217;s new Action Layer which itself will power many awesome primitives) is a major simplification to how coins can be spent on the Chia blockchain. If you&#8217;re interested in a high level explanation of how actions work, I&#8217;ve attached my presentation (in fact, the first formal presentation I&#8217;ve done before) from Chia Toronto.</p><div id="youtube2-S6bxdGIA9oQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;S6bxdGIA9oQ&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/S6bxdGIA9oQ?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h2>Database Redesign</h2><p>The wallet&#8217;s entire database schema has been rewritten from the ground up. There were a lot of motivators for this change:</p><ol><li><p>Since the database had been designed alongside the wallet, a lot of outdated or less informed decisions went into it. This led to unnecessary complexity, bloat, and tech debt (such as having to copy data to multiple redundant places in the database).</p></li><li><p>It was hard to add new features to the wallet, such as non-custody p2 puzzles (including clawbacks) and revocable CATs. Adding option contracts to such a database schema (which we plan to do later) would have been a nightmare.</p></li><li><p>A lot of information that is shared between each type of asset (XCH, CATs, NFTs, DIDs) was instead sporadically stored in various places. We&#8217;ve now consolidated it into a single assets table, for the most part.</p></li><li><p>Because natural keys (coin ids, puzzle hashes, etc) were the primary key in the database, queries with lots of joins became slow. This has been fixed by using surrogate keys (auto incrementing numeric ids) instead.</p></li></ol><h2>Revocable CATs</h2><p>A new <a href="https://github.com/Chia-Network/chips/pull/136">Revocable CAT</a> primitive has been introduced, and will first be used by <a href="https://www.permuto.capital/">Permuto Capital</a>. This is an add-on to the CAT standard that enables the issuer to revoke coins if needed. The S-1 filing details why and when this might happen, but in summary it&#8217;s due to legal compliance reasons. Almost all CATs that are not securities will continue to <em>not</em> be revocable (ie only the current holder has the right to spend the coin).</p><p>The <a href="https://vault.chia.net/">Chia Cloud Wallet</a> supports Revocable CATs already, so Sage now supports the standard as well for feature parity. However, due to the potential security risks of someone sending you a revocable CAT and misleading you into thinking it&#8217;s not revocable, there are various warnings and safeguards in place to make sure users are aware of which type of CAT they are looking at.</p><h2>Clawback v2</h2><p>A preliminary implementation of <a href="https://github.com/Chia-Network/chips/pull/150">Clawback v2</a> has been implemented in Sage. This might not be the clawback standard you are used to from the Chia reference wallet. Essentially, rather than the sender being able to claw back forever, they have a fixed time at which the ability to claw back expires (the same instant at which the recipient can spend the coins). This also means that the recipient no longer has to &#8220;claim&#8221; the coin by sending it to themselves.</p><p>While this new clawback standard can provide a better user experience, it comes with a couple drawbacks:</p><ol><li><p>If you forget to claw back in time before the expiration, you will not be able to. Make sure you set your clawback expiration time far enough into the future that you have enough time to react (and don&#8217;t forget)!</p></li><li><p>If you send a clawback coin to a recipient that doesn&#8217;t support the Clawback v2 standard (ie any wallet other than Sage at the time of writing this, but exchange wallets are known to not support clawbacks), you will have until the expiration to claw the funds back, since they won&#8217;t be able to receive it naturally. If you forget to do this, however, there is an additional way to spend the coins to &#8220;push through&#8221; the coin to the receiver. So the coins aren&#8217;t lost even if the receiver doesn&#8217;t support Clawback v2, it&#8217;s just more work to get it through to them.</p></li></ol><p>The original clawback standard remains unsupported at this time, however it may be implemented in the future depending on demand for it.</p><h2>Resyncing</h2><p>We all wish it weren&#8217;t the case, but unfortunately the wallet will sometimes fall out of sync with the current state of your wallet on the blockchain. Although improvements are constantly being made to Sage to reduce the need for a resync, it&#8217;s still required from time to time if something goes wrong.</p><p>However, there are a few major improvements to resyncing in this release:</p><ol><li><p>The default behavior for resyncing is now to preserve coin and asset data. This means that it will typically only take a few seconds rather than waiting for a long time for all of your coins to trickle back in. Instead of re-indexing everything from scratch it will only check for coins that are missing or out of date. However, you can still decide to delete additional data while resyncing if that&#8217;s not sufficient.</p></li><li><p>There&#8217;s a new &#8220;Delta Sync&#8221; option. The default behavior in Sage is to only look for and sync coins that are after the previous block height that you were synced to. However, if things happen in the wrong order and you end up with some coins missing (due to a race condition), you may need to resync. If you turn off Delta Sync, the wallet will check for coins it owns every time it&#8217;s started. This comes with a slight performance tradeoff, so it&#8217;s up to you whether you want to turn it off or not.</p></li></ol><h2>RPC API</h2><p>There is still no formal documentation for the RPC API, however I&#8217;d like to point out that there have been some breaking changes as a result of the refactors made in this release. Please check the <a href="https://github.com/xch-dev/sage/tree/main/crates/sage-api/src/requests">Sage RPC crate</a> for more details if you rely on these API endpoints. This API is not yet stable, so please use it with caution and pay attention to updates.</p><h2>Other Features</h2><p>There have been various other additions in this release, including:</p><ol><li><p>Support for viewing offers with <a href="https://chia-offer.com/views/home.php">chia-offers.com</a> short URLs</p></li><li><p>CSV export and offer sharing on mobile</p></li><li><p>You can now mint multiple editions of a single NFT at once</p></li><li><p>Offers work with fast forward (ie offer involving vaults)</p></li></ol><h2>Bug Fixes</h2><p>The following bugs have been fixed:</p><ol><li><p>You will now get an error in the UI if a transaction fails. Additionally, bugs relating to unconfirmed coins being left behind or coins you should own mistakenly disappearing until a resync should now be resolved.</p></li><li><p>NFT collections will now no longer be displayed if you don&#8217;t own any NFTs in them anymore.</p></li><li><p>The app would crash about every other time it was opened on iOS. This should be entirely resolved now, but please report any further crashes you run into.</p></li><li><p>Some UI errors could lead to blank screens. Known issues have been resolved, but if anything new comes up, please let us know.</p></li></ol><h2>Conclusion</h2><p>Now that all of this has been finished, I feel a lot better about being able to add new features in a shorter amount of time like we used to. You can expect more frequent Sage releases going forward.</p><p>The next feature that is yet to be released is <a href="https://github.com/Chia-Network/chips/pull/152">Option Contracts</a>. I was originally planning on including it in this release, but due to the amount of other changes being made and the complexity of the feature, I decided to punt on it for now so that it could be ironed out more.</p><p>Let us know <a href="https://discord.gg/sagewallet">on Discord</a> if you have any feature requests or find any bugs with the latest release!</p>]]></content:encoded></item><item><title><![CDATA[Advanced custody on Chia with vaults]]></title><description><![CDATA[Merkle trees, singletons, offers, oh my!]]></description><link>https://blog.rigidity.dev/p/advanced-custody-on-chia-with-vaults</link><guid isPermaLink="false">https://blog.rigidity.dev/p/advanced-custody-on-chia-with-vaults</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Fri, 31 Jan 2025 21:06:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TrN1!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When most people think of a crypto wallet, they most likely think of a 12 word (or 24 word) seed phrase or logging into an exchange app. I&#8217;m going to briefly explain how this works and how you can do so much better than this on Chia.</p><h2>The problem</h2><p>When you create a new wallet, you are generating a 12 or 24 word seed phrase and (hopefully) backing it up somewhere safe in case you lose it. Then, it gets imported into the app to be used to find coins and sign transactions. There are various potential pitfalls with this approach.</p><p>First of all, if you lose the seed phrase, there&#8217;s no way to sign transactions to spend your coins, so they&#8217;re effectively lost forever. As such, it&#8217;s important to back up the key in a secure place where only you can find it.</p><p>However, that introduces the second problem, which is that if anyone ever gets access your seed phrase they could immediately spend all of your coins without restriction. For example, if someone compromises your device or finds a backup you have saved somewhere of your mnemonic, you could lose everything.</p><p>For storing relatively small amounts of assets that you use on a regular basis, the risks associated with a hot wallet like this can be acceptable. However, it&#8217;s not sufficient if you need to custody a lot of funds or have multiple people that can spend them.</p><h2>Introducing vaults</h2><p>A vault is what&#8217;s known as a &#8220;singleton&#8221;. Like an NFT, it will always create a single new instance of itself when spent. You can use a vault to solve the problems described previously.</p><p>Let&#8217;s break down how that works:</p><p>Normally, when you spend a coin you need to sign a message with your private key. This means the key needed to spend the coin is encoded within the coin itself. With a vault, you are essentially extracting the custody out of the coin and into a standalone singleton. The vault can &#8220;authorize&#8221; the spend of the other coins.</p><p>This means that you don&#8217;t need to spend all of the coins to change the way you custody them. For example, if you decide you want to change which key you&#8217;re keeping the coins in, you can simply update the vault and they will all be implicitly &#8220;owned&#8221; by the new key.</p><p>However, in this scenario you are still using a single key to control the coins, which isn&#8217;t much better than before. Fortunately, vaults are very flexible and there are many different puzzle pieces you can fit together to make a vault more secure.</p><h2>Secp256k1 and secp256r1</h2><p>Standard transactions on Chia use what is known as a BLS key. These have very useful properties, such as the ability to aggregate multiple signatures together to save space. However, BLS keys are not as widely supported as other cryptographic signature schemes such as SECP.</p><p>K1 is commonly used on other blockchains such as Bitcoin and Ethereum. So, you could in theory achieve a higher level of interoperability with other chains by using this curve inside of a vault.</p><p>However, the biggest advancement in security on Chia involves the R1 curve, which enables you to use isolated hardware to sign transactions on certain devices.</p><p>Here is a couple examples that use R1:</p><ul><li><p>Apple&#8217;s Secure Enclave, which is embedded silicon in modern iPhones that allows you to store keys that can only be used by unlocking the phone. Additionally, it shouldn&#8217;t be possible to extract keys from the Secure Enclave, which means you can be confident that only you have access to them.</p></li><li><p>Passkeys (which can be used with the WebAuthn standard) allow you to securely store a key in your browser, device, or password manager. Signing is performed either on-device or by external FIDO security keys (e.g. Yubikey).</p></li></ul><p>The Chia Signer app created by Chia Network Inc allows you to use your iPhone as a vault signer on the Cloud Wallet.</p><h2>Multisig</h2><p>With a vault, you can use an &#8220;M of N&#8221; multisig instead of a single key. This is implemented with merkle trees as an optimization in some cases so that not every spend path needs to be revealed on-chain if they aren&#8217;t being used. Here&#8217;s a few examples:</p><ul><li><p>You could allow 3 people to have access to a vault with a 1 of 3.</p></li><li><p>With a 2 of 2, you can require two keys to always sign off on transactions.</p></li><li><p>A 3 of 5 would allow the majority to agree on whether to do a transaction without needing unanimous approval.</p></li></ul><p>This is pretty powerful since it allows you to decentralize the control a bit and prevent a single person from being able to spend all of the assets. It can help solve the &#8220;wrench attack&#8221; where a single person can be threatened into performing a transaction, since you require multiple people to sign off on it.</p><p>This gets a little into the weeds, but to expand on this further, you could in theory nest a multisig inside of another. For instance, if you want to require 3 of 4 people to do a transaction, but there&#8217;s a also separate pair of 2 that can do it instead. This would be a 1 of 2 with a 3 of 4 and a 2 of 2 inside of it.</p><h2>Delayed recovery</h2><p>With this advanced multisig setup, it&#8217;s more important than ever to make sure you don&#8217;t lose access to your funds even if you lose your phone, need to switch to a new one, or can no longer use a passkey.</p><p>With vaults, you can create a special &#8220;recovery key&#8221; that can be used to change the custody configuration of the vault if all else fails. However, you don&#8217;t want to give full control over the vault to this recovery key, especially if you&#8217;re using a multisig. Imagine if you have a 3 of 5 vault but one person uses the recovery key to take control.</p><p>To solve this, we use what&#8217;s known as &#8220;delayed recovery&#8221;. When you initiate a recovery of a vault, you can&#8217;t authorize spends for any of the coins. A time lock period for recovery (which is configurable beforehand) is kicked off. Using a watchtower service, each signer would get a notification that recovery has been initiated for the vault. They can then decide to cancel it (and remove the recovery key) or let it happen, until the time lock expires. Importantly, the new vault configuration has already been decided at the time of recovery being initiated, so you have confidence it will do what it says it&#8217;s going to do.</p><p>It&#8217;s worth noting that the recovery key is similar to the custody key in that you can configure it however you want. It could be a BLS key, passkey, or even a multisig.</p><h2>In conclusion</h2><p>With vaults on Chia, the doors are wide open to a future of better custody of digital assets. And combined with peer-to-peer offers, we&#8217;re able to have fully trustless and decentralized finance without sacrificing security.</p><p>Stay tuned for a more advanced deep dive into what you can do with vaults and how they interact with offers!</p>]]></content:encoded></item><item><title><![CDATA[The state of Rue Lang]]></title><description><![CDATA[Well, it's actually a stateless programming language]]></description><link>https://blog.rigidity.dev/p/the-state-of-rue-lang</link><guid isPermaLink="false">https://blog.rigidity.dev/p/the-state-of-rue-lang</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Tue, 17 Dec 2024 17:50:04 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/043cd56d-1b1f-475c-8821-fd065c311d41_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Rue is a programming language I&#8217;ve been working on designing for the Chia blockchain for the last couple years.</p><p>You can visit the <a href="https://rue-lang.com/">Rue Docs</a> and <a href="https://github.com/xch-dev/rue">GitHub repository</a> for more info, but keep in mind that the language is still very unfinished, as we&#8217;ll get into later. Keep reading to learn more!</p><h3>CLVM</h3><p>First, let&#8217;s start off with a bit of background. The Chia blockchain has an on-chain programming environment called <a href="https://chialisp.com/clvm/">CLVM</a> (the Chialisp Virtual Machine), which provides a set of low level opcodes which control the conditions under which a coin can be spent. I won&#8217;t go too into the weeds here, but will give a summary.</p><p>For example, take this program in Chialisp:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4AdS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4AdS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 424w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 848w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4AdS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png" width="1456" height="730" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:730,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:800319,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4AdS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 424w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 848w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!4AdS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc1b9505-2e8a-420f-9a88-79d579936e5e_2440x1224.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can think of a puzzle as a function that takes in some arguments (referred to as the <strong>solution</strong>) and returns a list of conditions. In this case, the <strong>AGG_SIG_ME</strong> condition (which roughly means aggregate signature for my coin) ensures that the public key has signed off on the conditions passed into the solution.</p><p>This compiles to the following CLVM bytecode, which is what is actually used on-chain:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!evQO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!evQO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 424w, https://substackcdn.com/image/fetch/$s_!evQO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 848w, https://substackcdn.com/image/fetch/$s_!evQO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 1272w, https://substackcdn.com/image/fetch/$s_!evQO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!evQO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png" width="1456" height="241" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:241,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:539780,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!evQO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 424w, https://substackcdn.com/image/fetch/$s_!evQO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 848w, https://substackcdn.com/image/fetch/$s_!evQO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 1272w, https://substackcdn.com/image/fetch/$s_!evQO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35c8f946-2c08-46d4-aad6-17de59393cd4_3680x608.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>It&#8217;s nearly impossible to figure out what&#8217;s going on without the original source code. So that&#8217;s why we have the higher level Chialisp language with a compiler to generate this. We sort of get the best of both worlds, it&#8217;s simple and efficient to execute when compiled, and readable by us humans before compilation.</p><h3>The Problem</h3><p>That was a pretty simple example of Chialisp, but it can get much more complicated.</p><p>For instance, this is the simplest example that illustrates my point that I could find, from the <a href="https://github.com/Chia-Network/chia-blockchain/blob/main/chia/wallet/cat_wallet/puzzles/cat_v2.clsp">CAT puzzle</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WTUA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WTUA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 424w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 848w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WTUA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png" width="1456" height="817" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:817,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:999564,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WTUA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 424w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 848w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!WTUA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64d97c4f-54f3-4fae-9933-f6915af0e413_2660x1492.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Lists in CLVM are made up of cons-pairs. In this case, a lineage_proof is structured like this (where f means first and r means rest, the two halves of the pair):</p><ol><li><p>(f lineage_proof) = parent_parent_coin_id</p></li><li><p>(f (r lineage_proof)) = parent_inner_puzzle_hash</p></li><li><p>(f (r (r lineage_proof))) = parent_amount</p></li></ol><p>So to know what this code is doing you need to know what lineage_proof is first.</p><p>Imagine if you could write code like this instead:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L956!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L956!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 424w, https://substackcdn.com/image/fetch/$s_!L956!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 848w, https://substackcdn.com/image/fetch/$s_!L956!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 1272w, https://substackcdn.com/image/fetch/$s_!L956!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L956!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png" width="1456" height="662" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:662,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1376416,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L956!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 424w, https://substackcdn.com/image/fetch/$s_!L956!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 848w, https://substackcdn.com/image/fetch/$s_!L956!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 1272w, https://substackcdn.com/image/fetch/$s_!L956!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9e29baa-7ee8-441e-a41a-5cfd67da2aea_3676x1672.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Sure, it&#8217;s more verbose, but with this you have the following benefits:</p><ol><li><p>The syntax is more familiar if you&#8217;re coming from a language like JavaScript or Rust.</p></li><li><p>Everything is strictly typed at compile time, so you can catch errors during development instead of at runtime.</p></li><li><p>Types like LineageProof are more clearly defined, so you can refer to the fields by name instead of having to manually index them.</p></li></ol><h3>Enter, Rue Lang</h3><p>The code above is written in a new language called Rue, which compiles directly to CLVM, just like Chialisp does. My primary goal with the language is to lower the barrier to entry to create smart coins on the Chia blockchain. I believe Rue has the potential to greatly simplify the development process, and make it less difficult to write secure code.</p><p>Like Chialisp, the language is &#8220;purely functional&#8221;, which means:</p><ol><li><p>Once you declare a variable, it cannot be modified. I like to think of it more as binding a value to a name rather than making a variable, since they can&#8217;t vary.</p></li><li><p>Functions themselves are values, so they can be passed around like any other. This is known as &#8220;higher order functions&#8221;.</p></li><li><p>There are &#8220;no side effects&#8221;. If you run a program multiple times with the same input, it will always produce the same output.</p></li></ol><p>However, there are a few key differences:</p><ol><li><p>As of writing, Rue has a more powerful type system (in fact, by default Chialisp is completely untyped).</p></li><li><p>It has a built-in standard library of common functionality you&#8217;ll need, like conditions and tree hashing.</p></li><li><p>You can export and import symbols from other modules. This could pave the way for making a package manager for Chia.</p></li><li><p>Generally, the syntax and scoping makes code simpler and reduces the number of surprises. That said, modern Chialisp has gotten a lot better in this regard.</p></li><li><p>There&#8217;s a proper language server that has type errors, compiler warnings, syntax highlighting, and in the future features like Go To Definition.</p></li></ol><p>The code produced by Rue and Chialisp are different, and currently it is not a design goal to make the outputs completely compatible with each other. However, the same program written in both languages should <em>behave</em> the same.</p><h3>So, where are we at?</h3><p>I got pretty far with implementing the compiler, and you can view the current codebase in the <a href="https://github.com/xch-dev/rue">GitHub repo</a>.</p><p>However, I ran into some issues when testing more complicated programs that illuminated underlying problems with the compiler&#8217;s code. The type system also still needs to be improved a bit. I haven&#8217;t completely decided whether to rewrite the compiler from the ground up or just redesign certain parts of it incrementally. But I have learned so much since I started the project that it&#8217;s tempting to start over (especially since I can&#8217;t easily resolve the current problems).</p><p>As you may know, I work at Chia Network Inc. In addition to that I also maintain Sage Wallet and the Chia Wallet SDK in my spare time, which pretty much takes up most of the free time I have. Because of this, I haven&#8217;t been able to dedicate as much time as I would like to working on Rue Lang, and it&#8217;s been left in this sort of broken state of which I can&#8217;t really recommend anyone to use it in production.</p><h3>What can you do to help?</h3><p>If you&#8217;ve read this far and are thinking &#8220;what is he on about&#8221;, that pretty much sums up my concern. It&#8217;s going to be difficult to find someone with the knowledge about or interest to learn all of the following:</p><ol><li><p>Chialisp</p></li><li><p>The low level CLVM runtime</p></li><li><p>Rust programming</p></li><li><p>Compiler design</p></li></ol><p>If you do and would like to help with the compiler directly, please reach out.</p><p>That said, if I&#8217;m being realistic I need to just find more time to work on it so that it can get done. Currently, much of my time is spent on Sage Wallet and the Wallet SDK, both of which are more approachable projects for people to contribute to. The more others can help out with the development of those projects, the more free time I have to work on Rue (and I greatly appreciate those who have already contributed).</p><p>I&#8217;m open to other ideas on how we can make this new language happen, if you have them. Open source development can be time consuming, but I believe it&#8217;s all possible, eventually.<br><br>Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Welcome to my blog]]></title><description><![CDATA[Collecting random thoughts about Chia development in one place]]></description><link>https://blog.rigidity.dev/p/welcome-to-my-blog</link><guid isPermaLink="false">https://blog.rigidity.dev/p/welcome-to-my-blog</guid><dc:creator><![CDATA[Brandon Haggstrom]]></dc:creator><pubDate>Tue, 17 Dec 2024 06:36:27 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%2F4aa0a210-19a6-440f-abc3-fbe19d510d74_837x837.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I work on many projects on the Chia blockchain, and I plan on using this blog as a place to share my designs, thoughts, and general pleas for help.</p><p>Here are some of the projects you can expect to hear more about:</p><p><strong><a href="https://github.com/xch-dev/chia-wallet-sdk">Chia Wallet SDK</a></strong></p><p>A collection of libraries for building apps (especially wallets) on Chia, including driver code for Chialisp puzzles, signing utilities, a simulator framework, and support for making and taking offer files.</p><p>I&#8217;d say this is the most widely useful project for the developer community, and it&#8217;s quickly becoming a foundational part of various ecosystem projects.</p><p><strong><a href="https://github.com/xch-dev/sage">Sage Wallet</a></strong></p><p>A performant and capable light wallet written using the Chia Wallet SDK. It connects to random peers on the network, syncs XCH, CATs, NFTs, and DIDs from them, and provides a good user experience for transacting with them.</p><p>There&#8217;s a lot of functionality that still needs to be added to Sage. In fact, there are <a href="https://github.com/xch-dev/sage/issues">50 open issues</a> at the time of writing this, mostly feature requests or UX improvements, but some of them are issues that need to be solved.</p><p><strong><a href="https://github.com/xch-dev/rue">Rue Lang</a></strong></p><p>Although still little more than a rough draft of a language, Rue is poised to be a promising alternative to Chialisp with a syntax that will feel more at home for most developers. It provides some niceties like compiler enforced typing, modules (although not fully implemented yet), compile time type checking enforce through runtime code generation, and a standard library.</p><p>I&#8217;ll be writing more about Rue and my plans for it in the next post.</p><p><strong>Puzzle Schema</strong></p><p>This is a project that hasn&#8217;t had much development yet since it relies on Rue Lang being in a more stable state. Essentially the idea is to make it possible to describe the driver code (which controls how coins are spent) in the same language as the coin&#8217;s puzzle is written in. These schemas could then be shared around and imported by wallets to enable them to support arbitrary custom coins.</p><p>This project, once completed, will improve ecosystem adoption of new primitives or combinations of primitives, by making the logic around spending coins more modular.</p><p>Thanks for reading! Subscribe for free to receive new posts and support my work.</p>]]></content:encoded></item></channel></rss>