Designing Bitcoin Smart Contracts with Sapio (available on Mainnet today)
3 messages, 9 to 16 Apr 2021. Started by Jeremy Rubin.
Jeremy Rubin (2), ZmnSCPxj
Bitcoin Developers,
I'm very excited to introduce Sapio[0] <https://github.com/sapio-lang/sapio> formally to you all.
Sapio empowers Bitcoin Developers to craft smart contracts in an intuitive, safe, and composable way. Sapio challenges the notion that you can't make complex smart contracts for Bitcoin, and opens the floodgates for a myriad of new ideas to be defined easily. Sapio works today on mainnet without any protocol changes (via user-configurable multisig oracles, it will work with BIP-119 OP_CHECKTEMPLATEVERIFY[1] <https://utxos.org> and Taproot when they are available).
You can learn more about what's possible by reading *Designing Bitcoin Smart Contracts with Sapio[2] <https://learn.sapio-lang.org>*. My Reckless VR Talk[3] <https://judica.org/blog/sapio/> also does a great job of breaking down the core programming model for Sapio contracts, although the language has evolved substantially since I gave the talk.
As a concrete instance of Sapio working in the wild, I am currently executing on mainnet a Congestion Control Tree[4] <https://utxos.org/analysis/bip_simulation/> contract with 25 recipients (the first Sapio contract to run on mainnet ever, as far as I'm aware). You can review the source code, arguments, compiler outputs, and transactions here[5] <https://gist.github.com/JeremyRubin/1374f0916bfdef0bd36bc10d73852886>.
To see more examples of what you can do with Sapio, the repo includes examples[6] <https://github.com/sapio-lang/sapio/tree/master/sapio-contrib/src/contracts> for derivatives, vaults, coin pools, games, side chains, and more. These aren't intended to be production grade contracts -- yet -- but are demonstrative of what can be built and how. I'm excited to see what people build -- please open up PRs with your ideas or any issues you encounter trying to implement them.
You can also try out Tux[7] <https://github.com/sapio-lang/tux>, an experimental GUI, to inspect, simulate, and interact with smart contracts. You can see the Congestion Control Tree mentioned earlier loaded in Tux below[8] <https://i.imgur.com/pg5SqfH.png>:
This is still early work-in-progress software, so tread lightly and use regtest. Enough of the components work today that it was appropriate to share now and invite more developers to contribute or otherwise support the project.
Sapio is developed free and open source for all bitcoiners by Judica.org (my organization).
Thank you to all who have helped reach this milestone of the first mainnet Sapio contract, including Ryan Grant, BitMEX, ACINQ, Delphi Digital, Backend Capital, my github sponsors https://github.com/sponsors/jeremyrubin, and numerous other supporters both fiscal and technical. I also want to highlight the excellent work done on Miniscript and the rust-bitcoin ecosystem, the foundation upon which Sapio rests.
[0] https://github.com/sapio-lang/sapio [1] https://utxos.org [2] https://learn.sapio-lang.org [3] https://judica.org/blog/sapio/ [4] https://utxos.org/analysis/bip_simulation/ [5] https://gist.github.com/JeremyRubin/1374f0916bfdef0bd36bc10d73852886 [6] https://github.com/sapio-lang/sapio/tree/master/sapio-contrib/src/contracts [7] https://github.com/sapio-lang/tux [8] https://imgur.com/pg5SqfH
Eager for you feedback,
Jeremy
Good morning Jeremy, et al.,
Quoted text (3 lines)
> Bitcoin Developers, > > I'm very excited to introduce Sapio[0] formally to you all.
This seems quite interesting to me as well!
I broadly agree with the rant on monetary units. In C-Lightning we always (except for some legacy fields that will eventually be removed) output values as strings with an explicit `msat` unit, even for onchain values (the smallest of which are satoshi, but for consistency we always print as millisatoshi), and accept explicit `btc`, `sat`, and `msat` units.
Hi ZmnSCPxj,
Funny you mention BlueSpec -- I actually took 6.175[1] in my undergraduate studies with Arvind, BlueSpec's creator, and have often cited it as an inspiration for Sapio given that the target of program compilation is essentially a transaction circuit and I have a decent amount of experience working in BlueSpec.
It's entirely the point that Sapio program expansion is Turing complete whereas the resultant program is "fixed". Via updatable finish clauses (which require some signature) it's also possible to track the logic for what states should be generated upon cooperation of parties, making Sapio turing complete description language for federated operators. I've previously described it as follows:
*But how is Sapio different from Miniscript? From Solidity? A metaphor that I like is that tools like Miniscript operate at the physical-key level (house keys, car keys, train pass, office key). Sapio operates at the commute level. Miniscript answers, "how do I unlock my car? How do I pay for the train? How do I get in my office?"*. *Sapio lets you specify that, "my morning commute is to leave my house, go to my car, start it and drive to the office, and park in the lot; OR go to the train station, use the train pass to pay fare, take the train for an hour, then* *walk 3 blocks north to my office; and in either case unlock the office door, and enter". Sapio has plans to integrate Miniscript as it stabilizes *[currently integrated]* as the backend key description language. Solidity and Sapio are more similar. Sapio's metaprogramming language is Turing Complete and allows you to specify a rich set of constraints for the contract you're building, but can only ever produce a finite deterministic "binary" of transactions. Solidity on the other hand compiles deterministically, but the executed binary is Turing Complete. Further, Sapio contracts are "stateless", whereas Solidity has mutable state. Lastly, Solidity contracts are non-isolated from one another in the EVM. In Sapio, contracts execute only with the components you specify in scope. In sum, Sapio has a rich descriptive power for smart contract programming flows but a limited and safe execution semantics.*
The DSL v.s. e-DSL is a great question, and while there are surely benefits to being a full-fledged standalone DSL, here's why the e-DSL approach is superior for everything Sapio cares about.
Sapio is built as a shallow e-DSL in Rust. Everything in Sapio can be expressed (macro free -- they're relatively light conveniences) as pure rust. There's also a more "API Like" interface where Sapio objects can be built out dynamically by other rust code easily. This means that if you wanted to come up with a custom DSL for a subset of Sapio programs, you could still very easily target Sapio (at runtime) as the AST processor. Said "SapioScript" can be an entirely separate crate targeting this base.
This is also nice because it keeps the Sapio core codebase relatively tight compared to what would be required were Sapio to be a "full language", and have tens of thousands of lines of custom lexing, parsing, type systems, etc etc.
Yes, you have to learn Rust, but Rust is one of the most popular languages for systems programming. It means that there's a library for almost any functionality you could want. There's tooling for building for any platform -- Sapio targets WASM happily, which helps with compile-once run sandboxed anywhere (this really helps for using Sapio as a replicated state machine for channels).
I agree with you that Haskell was previously a limiting factor for BlueSpec, but Rust is not Haskell. Rust is incredibly popular, and easier to learn (author's opinion) than Haskell, C++, or even Python (perhaps biased, but I always struggled with python for more than simple scripts knowing when objects were copied or referenced -- an initial version of Sapio was in python, but that codebase collapsed under its own complexity... and I had *great* MyPy coverage). It's certainly easier to learn Rust than to learn Sapio as a DSL -- Sapio requires learning an entirely novel way of thinking about structuring programs already, a DSL would require learning both the "Sapio Programming Model" and "The Sapio DSL". With embedded Rust, you can transfer all existing knowledge on Rust programming and add a veneer of Sapio.
Further Sapio is designed to not just compile to smart contracts as Bitcoin addresses, but be able to be deeply integrated inside of an application. For example, suppose you wanted to fetch keys for a contract from a database, query a network oracle for a state resolution, or something else. A DSL would scope creep infinitely or require numerous hacks, and at that point we're largely better off benefitting from the larger Rust community's efforts at providing excellent APIs for any task.
Therefore to make Sapio functional for building and deploying real bitcoin smart contract applications, a rust eDSL was not just the natural, it was the only choice.
W.r.t. to succinctness and "extra concepts" I'll admit that there is some disadvantage to Rust. There's a borrow checker -- which can be mostly defeated if you don't care about performance with Arc / Clone. You have to manually impl some traits -- but the trait system ends up not being bloat, but central to making contract state machines https://learn.sapio-lang.org/ch08-01-state-machines.html. And if you do actually look at the Sapio programs themselves, they are still quite succinct comparatively. I can imagine them being a bit shorter, but I think optimizing for the shortest possible utterance is an anti-goal for safety -- I aim for clarity. And that's where I don't exactly hate the borrow checker, since it makes it easier to tell when sub-contracts are using the same or modified data.
Best,
Jeremy
[1] http://csg.csail.mit.edu/6.175/archive/2014/index.html