<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Christian Rogobete</title>
    <description>The latest articles on DEV Community by Christian Rogobete (@soneso).</description>
    <link>https://dev.to/soneso</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1020321%2F8e88225e-c2ea-4bb0-9f6a-4b85e40cd982.png</url>
      <title>DEV Community: Christian Rogobete</title>
      <link>https://dev.to/soneso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/soneso"/>
    <language>en</language>
    <item>
      <title>Soroban contract with TinyGo</title>
      <dc:creator>Christian Rogobete</dc:creator>
      <pubDate>Tue, 07 Feb 2023 16:16:00 +0000</pubDate>
      <link>https://dev.to/soneso/soroban-contract-with-tinygo-3hm1</link>
      <guid>https://dev.to/soneso/soroban-contract-with-tinygo-3hm1</guid>
      <description>&lt;h2&gt;
  
  
  Invoking a soroban contract built with TinyGo
&lt;/h2&gt;

&lt;p&gt;This post describes my experience with building a simple smart contract for Soroban with TinyGo, deploying and invoking its function with the &lt;code&gt;soroban-cli&lt;/code&gt; and on &lt;code&gt;futurenet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I started on 5 February 2023 and at that time, the available TinyGo version was 0.26.0. The Soroban interface version of the host functions was 27.&lt;/p&gt;

&lt;p&gt;First, I installed &lt;a href="https://tinygo.org/"&gt;TinyGo&lt;/a&gt; and developed a very simple smart contract. It adds two &lt;code&gt;uint32&lt;/code&gt; values and return the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contract code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="c"&gt;//export add&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;toU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;toU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fromU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// main is required for the `wasm` target, even if it isn't used.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt;  &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c"&gt;// Extracts the 32-bit unsigned integer from a host value that represents a 32-bit unsigned integer.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;toU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Creates a host value that represents a 32-bit unsigned integer.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fromU32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;uint32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;  &lt;span class="n"&gt;addTagToBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Adds a given tag to a host value body.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt;  &lt;span class="n"&gt;addTagToBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="kt"&gt;uint8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, our function is called &lt;code&gt;add&lt;/code&gt;. It should add two &lt;code&gt;uint32&lt;/code&gt; values. As input parameters, it receives 2 host values (&lt;code&gt;uint64&lt;/code&gt;) and returns the result as host value too.&lt;/p&gt;

&lt;p&gt;First, we convert the received host values to &lt;code&gt;uint32&lt;/code&gt;, add them, and then return the result as host value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building with tinyGo
&lt;/h2&gt;

&lt;p&gt;Building with TinyGo first generates a huge &lt;code&gt;wasm&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tinygo build -o add.wasm -target=wasm -wasm-abi=generic add.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;



&lt;p&gt;&lt;code&gt;-rwxr-xr-x   1 chris  staff  56506  7 Feb 14:34 add.wasm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;However, TinyGo offers a few &lt;a href="https://tinygo.org/docs/reference/usage/important-options/"&gt;build flags&lt;/a&gt; and after some experimentation, I ended up with this command:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tinygo build -o add.wasm -target=wasm -wasm-abi=generic -scheduler=none --no-debug -panic=trap -opt z -gc=leaking add.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;First issue here: &lt;code&gt;-gc&lt;/code&gt;! It lets one specify the memory manager (garbage collector) to be used. There are 3 options available:   &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;leaking&lt;/code&gt; and &lt;code&gt;conservative&lt;/code&gt;. I wanted to use &lt;code&gt;none&lt;/code&gt; of course, but unfortunately that did not work out. It gave me the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tinygo:wasm-ld: error: /var/folders/w4/lcgfp2855g3f2k2_zs16tbnr0000gn/T/tinygo1603362656/main.o: undefined symbol: runtime.alloc
failed to run tool: wasm-ld
error: failed to link /var/folders/w4/lcgfp2855g3f2k2_zs16tbnr0000gn/T/tinygo1603362656/main: exit status 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More about this later ...&lt;/p&gt;

&lt;p&gt;So I ended up with the command above, generating a smaller (but still huge) &lt;code&gt;wasm&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rwxr-xr-x   1 chris  staff  3355  7 Feb 15:03 add.wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If one converts the &lt;code&gt;wasm&lt;/code&gt; file to &lt;code&gt;wat&lt;/code&gt; (textual representation), then one can read its content. It contains 1200 lines of code. See: &lt;a href="https://gist.github.com/christian-rogobete/4638ff024c23ce5cd9d142e3f3450be7"&gt;gist: add.wat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A lot of strange logic and 4 not so welcome exports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
(func $malloc.command_export (export "malloc") (type $t1) (param $p0 i32) (result i32)
    (call $malloc
      (local.get $p0))
    (call $__wasm_call_dtors))
  (func $free.command_export (export "free") (type $t5) (param $p0 i32)
    (call $free
      (local.get $p0))
    (call $__wasm_call_dtors))
  (func $calloc.command_export (export "calloc") (type $t6) (param $p0 i32) (param $p1 i32) (result i32)
    (call $calloc
      (local.get $p0)
      (local.get $p1))
    (call $__wasm_call_dtors))
  (func $realloc.command_export (export "realloc") (type $t6) (param $p0 i32) (param $p1 i32) (result i32)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, I decided to go forward with it and see if I can deploy the contract and invoke its &lt;code&gt;add&lt;/code&gt; function using the &lt;code&gt;soroban-cli&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding meta and contract spec
&lt;/h2&gt;

&lt;p&gt;As described in the Soroban docs, the &lt;code&gt;wasm&lt;/code&gt; module needs to contain 2 custom sections, &lt;a href="https://soroban.stellar.org/docs/sdks/byo#meta-generation"&gt;meta&lt;/a&gt;, describing the host interface version and &lt;a href="https://soroban.stellar.org/docs/sdks/byo#contract-spec-generation"&gt;contract spec&lt;/a&gt;, describing the exported functions.&lt;/p&gt;

&lt;p&gt;In AssemblyScript, the compiler frontend (asc) provides a mechanism to hook into the compilation process before, while and after the module is being compiled. This can be used with so called &lt;a href="https://www.assemblyscript.org/compiler.html#transforms"&gt;Transforms&lt;/a&gt; and &lt;a href="https://www.assemblyscript.org/compiler.html#hooks"&gt;Hooks&lt;/a&gt;, which allowed me to add the 2 custom sections to the module in the &lt;a href="https://github.com/Soneso/as-soroban-sdk"&gt;AssemblyScript SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, in TinyGo there is no such mechanism. After a question in the TinyGo Gophers slack channel one of the maintainers suggested to compile the sections separately and link them using a CGo flag: &lt;code&gt;#cgo LDFLAGS: somefile.o&lt;/code&gt;. But after searching more for a solution, I found &lt;a href="https://github.com/tetratelabs/wabin"&gt;Wabin&lt;/a&gt;, which allowed me to programmatically add the 2 custom sections to the compiled module.  &lt;/p&gt;

&lt;p&gt;Here is a gist containing my code doing so:&lt;br&gt;
&lt;a href="https://gist.github.com/christian-rogobete/1b8d2506f270938de1d4b3b0aefc7dce"&gt;addsec.go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally! I had the sections added and I was ready to invoke the &lt;code&gt;add&lt;/code&gt; function using the &lt;code&gt;soroban-cli&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Inspecting the contract
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;soroban-cli&lt;/code&gt; offers an inspect functionality that inspects a WASM file listing contract functions, meta, etc.  &lt;/p&gt;

&lt;p&gt;I tried that first and here is the result:&lt;br&gt;
&lt;code&gt;soroban inspect --wasm add.wasm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;File: add.wasm
Env Meta: AAAAAAAAAAAAAAAb
• Interface Version: 27
Contract Spec: AAAAAAAAAANhZGQAAAAAAgAAAAF4AAAAAAAAAQAAAAF5AAAAAAAAAQAAAAEAAAAB
• Function: add ([ScSpecFunctionInputV0 { name: StringM(x), type_: U32 }, ScSpecFunctionInputV0 { name: StringM(y), type_: U32 }]) -&amp;gt; ([U32])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks good! :) &lt;/p&gt;

&lt;h2&gt;
  
  
  Invoking add
&lt;/h2&gt;

&lt;p&gt;Command:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;soroban invoke --wasm add.wasm --id 1 --fn add --arg 2 --arg 3&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: HostError
Value: Status(VmError(Validation))

Debug events (newest first):
0: "Validation"

Backtrace (newest first):
0: backtrace::capture::Backtrace::new_unresolved
1: soroban_env_host::host::err_helper::&amp;lt;impl soroban_env_host::host::Host&amp;gt;::err
2: soroban_env_host::vm::Vm::new
3: soroban_env_host::host::Host::call_n
4: soroban_env_host::host::Host::invoke_function
5: soroban::invoke::Cmd::run_in_sandbox
6: soroban::run::{{closure}}
7: &amp;lt;core::future::from_generator::GenFuture&amp;lt;T&amp;gt; as core::future::future::Future&amp;gt;::poll
8: tokio::runtime::park::CachedParkThread::block_on
9: tokio::runtime::scheduler::multi_thread::MultiThread::block_on
10: tokio::runtime::runtime::Runtime::block_on
11: soroban::main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oh no, no, no! Now go and find the reason! :)&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0: backtrace::capture::Backtrace::new_unresolved&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;is this line of code in the &lt;code&gt;soroban-env-host&lt;/code&gt; rust code (in &lt;a href="https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/host/error.rs#L114"&gt;soroban-env-host/src/host/errors.rs&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt;  &lt;span class="n"&gt;backtrace&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nn"&gt;backtrace&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Backtrace&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new_unresolved&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I had managed to build &lt;code&gt;soroban-env&lt;/code&gt;, write a test and try to debug it, I was tortured by the thought that I have to get rid of the strange logic and the malloc like exports from the module.  &lt;/p&gt;

&lt;p&gt;But &lt;code&gt;-gc=none&lt;/code&gt; didn't work, so I decided to ask in the TinyGo Gophers slack channel again.  After some discussion, a maintainer of TinyGo pointed out a current &lt;a href="https://github.com/tinygo-org/tinygo/pull/3142"&gt;pull request&lt;/a&gt; that aims to get rid of that exports and their logic (which were exported by accident).&lt;/p&gt;

&lt;p&gt;Ok, sounds good, but when will this be available? Probably in the next version. But I wanted it now, so I decided to build TinyGo from that branch and try again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building TinyGo from the wasm-no-malloc branch
&lt;/h2&gt;

&lt;p&gt;On the TinyGo website there is a &lt;a href="https://tinygo.org/docs/guides/build/"&gt;description&lt;/a&gt; of how to build TinyGo for development.&lt;/p&gt;

&lt;p&gt;With the new built version I tried it again:&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the new wasm file
&lt;/h2&gt;

&lt;p&gt;Command:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.../build/tinygo build -o add.wasm -target=wasm -wasm-abi=generic -scheduler=none --no-debug -panic=trap -opt z -gc=none add.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-rwxr-xr-x   1 chris  staff  456  7 Feb 16:08 add.wasm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;cool! &lt;/p&gt;

&lt;p&gt;and now optimize with &lt;code&gt;wasm-opt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wasm-opt -Oz add.wasm -o add.wasm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-rwxr-xr-x   1 chris  staff  313  7 Feb 16:10 add.wasm&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;even better, &lt;strong&gt;313&lt;/strong&gt; bytes and we started with &lt;strong&gt;56506&lt;/strong&gt;! See the new &lt;a href="https://gist.github.com/christian-rogobete/d9c4c5a5e285d58dbb5eb56e614d26d8"&gt;wat file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, add the custom sections to the module and try again with the &lt;code&gt;soroban-cli&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;soroban invoke --wasm add.wasm --id 1 --fn add --arg 2 --arg 3&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;code&gt;5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Tadaaa! &lt;/p&gt;

&lt;p&gt;And same on &lt;code&gt;futurenet&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EW2Jc1Se--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uuekdk4ybkzevt5efczy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EW2Jc1Se--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uuekdk4ybkzevt5efczy.png" alt="futurenet" width="805" height="646"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We can now build contracts with TinyGo and start experimenting. In the upcoming version of TinyGo - 0.27.0 - the pull request will hopefully be merged, so we don't need to build TinyGo from the &lt;code&gt;wasm-no-malloc&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;There is still a long way to go, but a first proof of concept is here. Maybe this will end up in a new Soroban SDK for TinyGo ;)&lt;/p&gt;

</description>
      <category>soroban</category>
      <category>sorobanathon</category>
    </item>
  </channel>
</rss>
