Sway: Developing a Smart Contract for FuelVM, an Optimistic L2 -Alex Hansen -@SwayLang @ETHDubaiConf
ETHDubai 2022 · 31 Mar 2022 · 27:53
Alex Hansen compares Sway with Solidity and Rust, covering contract storage, types, enums, exhaustive matching, and inline assembly for FuelVM. He introduces the Forc toolchain and Rust and TypeScript SDKs, then answers questions about target applications, Vyper, editor support, and migration tooling.
Speakers
Topics
From ETHDubai 2022, hosted by DeFi Dubai.
Transcript
uh so we are going to be walking through some of the pros and cons of using sway what it's like to develop smart contracts for the fuel vm and uh just some general use cases through this talk this talk does presume some level of elementary familiarity with solidity programming preferably rust but not necessarily because this is a the syntax is very rust-like this will also contain a lot of code examples and a b comparisons essentially amounting to tutorial or intro to sway for somebody who only knows solidity and yeah i'll go ahead and get started cool so we'll go ahead and start by kind of top down what is what is the uh market that we're
addressing what is our motivation uh sway was motivated by both solidity and rust so in solidity obviously it's like the prominent smart contract development language and it brought the whole notion of smart contracts into everyone's mind and it's extremely powerful we believe in the rust philosophy of language design and we want to combine the ergonomic first class smart contract and blockchain support of solidity with the design philosophy of a language like rust what we generally mean by that is that we want to provide security and static analysis in exchange for auditing and being very careful so the programming model is pretty
similar to ethereum although we allow for multiple native assets and this removes the error class of you know rolling your own token from your contracts entirely there have been a couple of prominent vulnerabilities along that space and that's that's kind of like what you would gain from coming from solidity but to talk about the rust side of things chromium has done a study of all of the bugs that they have they have encountered over the past i don't know n years we'll have to check the study and most of them related to memory unsafety problems and among memory unsafety problems there's a couple different classes but most of these are addressed by a
programming language called rust now this is not a blockchain language this is just a general purpose programming language but what they were able to do is through language design and through static analysis they were able to essentially eliminate an entire class of bugs an entire class of bugs that represented 70 of the chromium projects bugs so just by virtue of language choice you're already your entire space of bugs is only 30 of what it used to be which is huge and we essentially want to do that for the smart contract development space um obviously memory safety bugs are not exactly a huge issue in the smart contract development space because you know it's a different it's a different problem domain so we do not specifically tackle things like the borrow checker or
use after free or things like that mainly because they're not relevant instead we provide blockchain first static analysis so things that typical contract vulnerabilities that you would want to catch an example of that would be a violation of the chex effects interaction pattern we can provide static analysis to warn you and prevent you from doing that without ever having to hire a single auditor um and if you want to see they also have a pie chart about the various memory on safety bugs they had in chromium uh right so we're essentially my thesis here is that we're combining a lot of aspects of rust in a lot of aspects of solidity so from rust we get a statically typed verbose and friendly
compiler we get the syntax of rust we get trait-based inheritance so i don't know how many of you have dealt a lot with solidity inheritance structures it can be opaque and the evaluation of constructor order can be um ambiguous at times not technically ambiguous but it's difficult as the programmer to analyze we also from rust package we package our compiler with a lot of tooling so one of the things that russ does great is is cargo so before i keep going has anybody here used cargo before maybe a show of hands cargo okay about like 15 so cargo is a package manager a builder a documentation generator a augmentable plug-in system
um a testing framework a benchmarking framework all of that in rust in this one single binary and what that gives you is that gives you one enshrined way to do things so you get a unification of documentation you don't you just skip that whole decision process of your tooling for a lot of these things it gives you one unified way to build your project and it gives you a lot of ergonomic benefits so we package sway with something extremely similar to cargo we'll get back into that later but essentially uh it's a a battery's included pack you just download the single binary and you get going in addition to that we have a unified team so our tooling team our language team
our formatter team our vm team we're all we're all in the same chat here right so we literally the same slack channels so we're able to share a lot of code we're able to unify our tooling the main dichotomy that i'm drawing here is if you're writing a solidity smart contract you also need to onboard into javascript typically and use hardhat and you need to decide which testing framework are you going to use you need to decide you have to make a lot of decisions and you have to accept a lot more liability having one enshrined tool chain eliminates a lot of that so what did we take from solidity uh well our language is designed primarily around smart contract development we integrate contract storage as a
built-in language construct so with a lot of other rust-based smart contract languages you'll see essentially storage access or other contract primitives as library functionality or as syntax syntactic sugar or something like that we have contract storage as a first class language construct but we try to do it a little bit safer than solidity we want shareable contract interfaces so if you're writing something to call a contract or if you want multiple deployments to implement the same interface we want that to be able to be shared and we want that tool to feel like it was made for the task so you want to use the right tool for the right job there are a lot of other projects that essentially bolt into rust
or use llvm or like an alternate llvm back end for the task of writing smart contracts and what ends up happening is your front end was engineered for an entirely different purpose and so you end up throwing away a good chunk of functionality and bolting onto a very specific subset and it's just not an ergonomic feeling and when you don't feel ergonomic writing code that is you know deploy once live forever you're going to end up with vulnerabilities so we are fuel and our what we want to do here is we want to provide fast and efficient contract deployments and execution and we want to provide safe safe code we want everything to be easily auditable we want you to feel safe when you're deploying any sort of
contract written in sway we will maintain semver and backwards port security fixes which is something that has been a point of contention in the smart contract development space and we generally just kind of keep an eye on twitter and we uh we learn from angry tweets as well i would like to mention that and uh we unify the tooling and developer experience as i mentioned before um so i'm just going to slightly tongue-in-cheek show a couple of angry tweets we've learned from so um yeah so this one well i'll just i'll just play these really quick so yeah we also don't have don't have
that and uh yeah okay so some people would say that rust is definitely something that's hard to hard to learn but you know we're not we're not writing rust so we we aim to have a lot of really good documentation and a lot of really good developer onboarding okay so i'm going to start getting into like the nitty gritty language features uh specifically state variables so when you're accessing contract storage or contract state then um in solidity it looks a little something like this and this variable is essentially in your scope now you have uh you have the stored data variable and this in itself has of course led to some vulnerabilities this ambiguity between which variables are store or storage and which ones are not
so what this looks like in sway is we have this uh the storage declaration which looks really similar it's a little bit different syntax but we have the storage keyword and we have it looks like a struct declaration essentially and now to access that storage you have to a and your function annotate that you are accessing state with that annotation there that says storage read write and you also have to prefix your access with the storage keyword now this seems like maybe something trivial you're like oh it looks like a struct or an object access in any other language but in reality this would have prevented large vulnerabilities oh i've done something to my presentation in reality this would have prevented
quite a few vulnerabilities that are out there right now where there's ambiguity between whether or not you're accessing storage or whether you're accessing just the local variable all right now we'll take another look at a couple code examples here so functions and solidity i'm sure nobody needs a refresher um they look more or less like this you have attributes that you can attach onto your function signatures [Music] you have things like pure you have payable etc just to give you a little bit of the syntax in sway it's going to look a little bit different so you define your abi completely separately your contract api and this grants you a couple of
things so one is that you can share this api you can export this api and when you call this function you can just import the api and use it directly as if it was you know just a library um and then we're going to implement that api for our contract and you know you implement the functions it looks a little bit like a trait if you're familiar with rust and one final little thing is that we have implicit returns down there so you see that there's no return keyword in the helper function and then to go back a little bit to a different example instead of having things like pure payable etc etc we have these annotations on top of functions function signatures so that's just a syntactic
difference yeah and we've replaced the solidity inheritance constructor system as i mentioned before with a trait-based inheritance system if you're familiar with haskell it's kind of like a type class if you're familiar with java um it's gonna be a little bit more like an interface all right another thing that we want to look at is error handling and how you actually would handle an error case in a contract so one thing that we really like and want to keep using from solidity is being able to just revert in your control flow this is not actually the case with all platforms out there right now so we want to be able to retain that so reverting in your control flow is is great because you either you want to do one thing
right or revert that's like a really good design principle so in order to keep this um keep this principle we have retained that as well and it looks like on this computer my fonts are a little bit different so so we get a scroll bar unfortunately um by the way just since we see the scroll bar if uh if you ever want to look at this code right now or something the url is up there at the top you can just browse to it and look along you can even read my speaker notes um so that got a louder we have uh the panic macro which i am okay we'll move on from this one we have [Music] here it is okay
so scroll bar is a little bit less bad here but we have the transfer function here which returns a result so this is what's called a sum type and we have enumerations in in sway and uh what you do here is you can return an error and if you're familiar with this what this does is it instantiates one type of the sum type and then that can return from your contract all right so another thing we have is a along with our static types we have a pretty advanced and robust type system we have generics we have type inference we have structs and enums which are also known as sum and product types or if you're particularly mathy and maybe even silly they're called pi and
sigma types so what those generally look like is this so struct if you're familiar with rust this is almost almost the exact same syntax um the enums are a little bit different but if you're familiar with rust a struct declaration you're now declaring two u-64s unsigned 64-bit integers that'll be stored in memory contiguously there's no overhead here there's no run time the size of the not enough funds struck is 128 bytes or bits it is two u64s concatenated together and that's called a product type and then for the sum type in the enum you have one or the other so instead of having memory being laid out
contiguously in an enumeration you are either one or the other this does have a little bit of overhead there is a tag stored so you have essentially 64 bits more than the size of the largest type and as you see here we have generics as well so generic functionality so that you can share this some type over all your other types so our type system is essentially the same as rust but with a few differences uh primitive types are mostly from solidity there's a lot of primitive types and rust that you don't really need when you're developing a smart contract so our primitive types include unsigned integers booleans static length strings 32 byte values single byte values and the unit type also known as the empty tuple
and we also have tuples as well to compose these types as mentioned before we have generics and traits and traits with inheritance so if you're familiar with rust syntax this will be pretty familiar if you're not a quick explanation is that the trade is called foo so this is like i said a type class if you're familiar with haskell or java it's a it's like an interface you're essentially opting into some interface for your type so this trade here uh is essentially saying we're going to define a trait foo that is generic over two types and the first type requires that it also implements the interfaces bar and baz and the second type e requires the interface
i've actually never had to pronounce this out loud kooks there we'll go with that um yeah so that's our type system and then a couple of literal instantiations we have here so generally instantiating a variable you can provide a type annotation optionally or you can allow inference you can we have b256 literals etc etc so we can dive a little bit into the use cases of a union type a discriminated union which is a sum type also known as an enum so um this is an example of composing those two things so you have the structs with your contiguous memory layouts and then you have the enumeration sale
so the the struct service is the larger of the two because it has a 15 character long string and thusly the size of sale if you remember what i said earlier is the tag plus the larger variant so it's going to be the size of service plus 64 bits cool additionally we have match expressions so similar to rust you have control flow where you can put an if or a match on the right hand side of an assignment and what that does is it's just it's a very expressive way of writing your code and not only do we have matches as expressions but we have exhaustivity
checking so there's actually if you were to try to compile this you would get an error because you are not covering the domain of numbers from three to infinity and exhaustivity checking is another thing that prevents essentially prevents vulnerabilities vulnerabilities oftentimes come from control flow that the programmer did not anticipate and if the compiler is able to look at the control flow and say hey there's a case here that you've missed you will not have an unanticipated case or undefined behavior in your control flow so another quick example we'll dive into here is ec recover so if you use ec recovery in solidity and it fails you get a magic
magic constant back [Music] doesn't quite fit with this font and that magic constant is just a bunch of zeros and this is a general generally considered as kind of a programming anti-pattern because what you have is is a sentinel value that represents something however the sentinel value is within the domain of what could have hypothetically been returned from the function in a valid use case and what this means is that the programmer has to remember programmer has to remember to check for this every single time if not that's a potential source of vulnerability and in ethereum this is not an issue but in general this is also a opportunity for somebody to like hijack whatever the sentinel value is and
that could lead to a compromised account or something like that so one of the reasons we're really big on some types and enumerations is that they completely prevent this some types and exhaustivity checking together completely prevent this so some types enforce that all cases are handled properly sorry exhaustivity checking and forces that you've handled all the cases that are possible in your control flow and a sum type would fix this by essentially returning either okay or an error if it's okay you get the value just fine if it's an error then you you know for a fact that the ec recovery does not work you don't have to check a magic constant there's a zero percent chance that you are going to accidentally treat the error value as
an address and then proceed all right okay so just a quick speed round of language features time is coming to an end here ifs our expressions uh we have oh yeah we have unchecked arithmetic as well as checked arithmetic without runtime overhead that's due to our vm architecture we have pretty sweet underscore syntax just another little thing matches our expressions okay i'll skip over let's give over visibility for time's sake um both solidity and sway support writing inline assembly but swiss and sway's standard library is implemented in this construct the way in which we do this is
a little bit lower level for now so in solidity an assembly block looks something like this and you'll if you're an optimizer you'll end up doing this a lot and in sway assembly blocks look a little bit more like this you initialize some registers to some values so in this case the register r1 is initialized to a r2 is initialized to b we add those two so if you're familiar with like uh mips or x86 style assembly r3 is the destination so we're adding r1 and r2 putting it in r3 and then returning r3 um with an implicit return a couple more assembly examples here you can put any arbitrary expression in
the initializer of your assembly uh see okay cool so the final point that i want to hit here in the last five minutes is our tooling and i think this is honestly the biggest selling point so the language itself sure it's like learned a lot from modern language development and modern language design and it tries to make everything safe and tries to make everything ergonomic but in addition to that we package it with good tooling and one of our main points of pride is this thing called fork so our organization is called fuel and this is stands for fork or fuel orchestrator and this is going to be your cargo this is going to let you build this is going to let you test this is going to let you eventually audit your code this lets you
initialize new projects etc etc and all of this is completely enshrined it's all it's all open source as well but it's like the enshrined and recommended way of doing things and we also subscribe to the rest philosophy of one way to do everything and that one way should be the correct way and it should be also the most efficient way we also have two sdks available for dealing with our contract code so the russ sdk what it does is it allows you to test deploy to a node do all sorts of things both of these sdks allow you to do that and you can do them either from rust or from typescript so this is going to also not quite fit on the screen up here but um
this is just an example of the rust code that you would see if i can do this the rust code that would be used to for example load a contract can i can i do it from here load a contract and interact with it from rust using our sdk we don't need to delve into this in too much detail but you can get a general idea for the fact that we have an ergonomic api that surrounds contracts and rust so that you're able to programmatically deploy and test repeatably and with just three minutes to spare i will wrap it up thank you all for listening check out sway if you're interested in using it
we have an email there dev program at fuel.sh we also have a discord server we have multiple twitters uh swaylang has a twitter as well and yeah that's all thanks a lot i wanted to ask actually what's your target audience for this language so what types of products should be built with this yeah so that's a good question so just to give you some context i'm the compiler guy i work on primarily the language but uh our we also have a layer two roll up and we also have a modular blockchain execution layer and so if you're interested in layer twos and scaling in general uh this is like a perfect chance to dive in there's a lot
of i know there's a lot of competing contract development platforms in the layer two space but you know this is one of them uh so that's one use case another thing is if performance is really key so you have maybe high volume trading and you're worried about gas fees or things like that that's a really good use case but it is a general purpose contract development platform so ideally any contract where you care about security and performance could be applied here okay but but it's compiled it's even compatible yeah actually it's not so um we do have a evm compatible vm and that's part of the optimistic roller project however this language targets specifically the fuel vm op codes so that's in that way it would be evm
compatible although we've recently pivoted to essentially working more with uh celestia if you're familiar with a company called celestia and providing the first modular blockchain execution environment and we aim to be the fastest in that space great thank you very much any more questions okay um how would you compare the language with viper ah yes so viper for those not familiar is like a python based smart contract development platform as well uh viper is really cool and uh yeah i mean it's definitely a really cool product um we're kind of taking a different design philosophy though obviously for two main reasons one is we're targeting the fuel vm and uh our specific layer two and that involves
entirely different op codes and so we're not really able to leverage things like viper for our tool chain and that's just kind of necessarily why that justifies the existence of this project but additionally in language philosophy like i mentioned i'm like the language guy and in language philosophy very different python has a lot of a lot of pros about it but we're definitely more interested in static analysis security auditability things like that at compile time so we want the compiler to be able to tell you hey this could be a vulnerability that could be in your contract and i uh it's not as high of a priority as far as i'm aware in like the viper toolkit all right
any more questions oh yeah something easy thank you very much um in fact i've got three questions very quickly one about remax is there any plan to support the language via remix itself as an ide and question number two is there any porting tool like i already have my own solidity smart contract and i would like to port it or convert it to be using sway language and question number three in the market there is a
very famous library open zeppelin um is there any way to utilize it or is there any chance that this library is going to be ported to sway okay yeah so uh just to give some context we're still a pretty relatively early stages project we're about a year in and um i'm going to kind of answer these well i'll start back to front since i remember them uh so question three open zeppelin it would be great to have tooling like that available um we're still a pretty early project and um we ourselves haven't invested the resources and implementing it in the inside of our organization it would be great if once it's out there and we're seeing more
adoption it's entirely possible that somebody would implement that or even that we would we would pay to have that implemented uh but that's just that's not right now we're still working on core language development and and the tool chain itself uh question two was a transpiler so like going from solidity to sway that is also something that would be obviously really good for us to have for adoption's sake but that's a really hairy problem especially when the destination language is still being developed so that's one of those maybe someday things it would be really great but i know there's i believe there's one for cairo right that you can go from solidity to cairo i think if i'm not mistaken and that's like a really cool thing but um yeah we don't have that yet and the first one you said limits was
that linux ide oh emacs did you say oh okay yeah first of all as part of tooling we have a vim plugin and a vs code plugin unfortunately not e-max but we have a core language server so for emacs if you have i i'm personally a vm person so i'm sure there's a language server protocol that's emacs compatible that you could use but we do have a language server yeah anything else is that it or any more questions okay it seems that we're done thank you you're really done cool stuff
please check it out you