Developing Smart Contracts in Sway

ETHCC 5 · July 2022 · 48:06

Emily Herbert introduces Sway, the Rust-influenced smart-contract language for Fuel. The workshop demonstrates starting a project and developing, testing and deploying contracts within the Fuel ecosystem.

Speakers

Topics

From ETHCC 5, hosted by Ethereum France.

Transcript

oh okay uh yeah so my name is emily i'm here with fuel labs and today uh we'll be doing a workshop on developing your first smart contract using our language sway so i'm hoping that today we can do a fairly interactive workshop we have a bunch of the sway team here with us sway team please raise your hand uh so i think it would be really fun if we could do something interactive while you all have the opportunity to have the team here in the room with you and get to know us get to know the the tool get to know the language so we'll do a little intro about what is sway

a little intro about how to use it and then we'll dive into the workshop so uh can i see a raise of hands of maybe how many people have their laptops and how many people might be following along on their laptops today just to get a gauge okay so in that case i'll also be working on the screen so that everyone can see what i'm doing and can get a feel for the language as well what is sway sway is a blockchain language that is used for developing smart contracts it is written for the fuel ecosystem and it takes from both solidity and from rust

so from solidity it takes a lot of the blockchain focused design elements that you might be familiar with so you can call contracts you can write smart contracts in general you can have contract storage and more and then from rust it takes a lot of the general language design and it takes a lot of the design principles the general feel the ergonomics and the developer experience so when we're designing sway we're really hoping to kind of couple the two uh the two benefits of the two languages so offer you the ability to develop for blockchain while als also offering you the awesome benefits that rust provides both in its ecosystem and its

user experience and its feel sway is the language that is used on the fuel network in the fuel virtual machine i won't get into that too much today so if you're interested in learning more about fuel and the benefits of fuel you can go to our website fuel.network it's a little bit light on this screen but the website is just fuel dot network and you can learn more about the fuel vm and the fuel ecosystem just in broad strokes the fuel ecosystem you can think of it as part of a modular blockchain so it's a modular execution layer and its main goal is to do execution

with the fuel virtual machine using highly parallelizable utxo based transactions with the smart contracts written in this sway language so we'll be learning sway today and then the contracts that you'll be writing will be executing on the fuel vm on the fuel ecosystem so for the people following along there's two installs that we need to do right off the bat and so we'll get those started and then we'll dive into the primer about sway so the first one is installing cargo i'll just pause for a few minutes for everyone to install cargo i don't really know how long to wait so

um i feel like is everyone the people that want to install cargo have y'all installed cargo okay i will take that as a yes uh so then the next thing is you will need to install fork fork is the project independency management system for fuel and you'll install it using fuel up fuel up is very similar to rust up which is used to install rust and cargo so you'll install it with this i just made a tiny url for it the install for this one takes a few minutes so we'll just get this one started and then proceed with the rest of the slides again i'm not really sure how long do i

wait for this so if you still need this uh let me know and i can go flip back to the slide uh while this is installing i'll just do a quick five-minute primer about sway and this will give us enough information to where we feel like we can dive into learning how to write our first sway contract so when you're working with sway there's of course the language itself which is sway the language has syntax it has its design but then you need to be able to use it you need to be able to build it compile it deploy it and the way that you're going to do that is with fork fork is the project independency management

system for sway you will use fork to compile build deploy and test your contracts you'll use it to start local fuel networks and more so that's what we installed in the last slide to give you an example of what fork can do when you want to create a new project you can use fork new pass it a name tell fork that you want to create a new contract and fork will create a new empty contract for you so we can see here that fork has created a skeleton contract structure for us and at a high level every sway project has four components it has

the cargo.tamil fork.tomall the source directory and the test directory and i'll describe what each of those means so the fork.tamil file has all of the information in it that fork needs to build your sway project and deploy the contract so this is like the name the dependencies the version information like that then the source directory has the contents of your sway code and the main.sway file is the entry point to the project the test directory has your sway tests and you'll see here that the test directory has a harness.rs file so that you may notice that this is a

rust file and that's because in a sway project you can do testing with rust you can write your tests in rust using the fuel rust sdk so the rust sdk allows you to do all the things that you would do with fork so compile deploy test sway contracts and it also allows you to spin up a local fuel network and more all in rust and that leads us to fork dot tom mall essentially fork uses cargo under the hood so the cargo.tml file helps fork understand how to build this project to build a sway project you can run fork

build we can see here that we've built our project successfully and then to run the tests that i mentioned on the previous slide you can use fork test now we'll talk a little bit about the language definition of sway which will help us understand what we'll see in the example in sway you can have variable declarations so to declare a variable you will use the let keyword to declare immutable variable you use the mute keyword and then you can also add type descriptions with this type description syntax you can have functions so here we have our function called function name with our two

parameters param1 for m2 and it returns a string of length 4. in a sway contract you define the avi and then implement the abi for the contract and it's done as such so you will define the api using this api keyword so here we have our api called simple auction the api has one function bid and then we implement the abi for contract and we implement the contents of our one api function bid with the body of the function this is

beneficial because this means our abi definitions are exportable and shareable so in this particular example the abi definition is co-located with the implementation but with a sway contract you could potentially separate the abi definition from the implementation and you could write a sway library that has the abi definition and you could make that library shareable and you can implement multiple contracts using that same library and you could share that library with your friend and your friend could write their own contract using that same api definition and it allows you to really expand the scope and make those apis shareable sway has contract storage and contract

storage is accessed using the storage keyword so here we have the storage keyword and in this example we have one element in our contract storage called my data which is a u64 initially set to zero to access contract storage uh you need to create a function and and above that function you need to annotate it with this special annotation here this annotation tells the sway compiler that you want to both read from storage and write from storage this allows the compiler to make certain guarantees and optimizations and perform efficient auditing to access storage you use the

storage dot syntax so here we can say we're retrieving our old data we're saying storage.mydata setting it to a variable and then we're updating storage.mydata with the new data and then returning the old data expanding on this idea sway also offers a mapping type for storage called storage map so here we have our storage our contract storage again and we have the my map variable and the my map is a storage map mapping a u64 to a boolean value so you can think of this like a number two if that number is on or off

and it's initially set to an empty storage map if we want to insert a number into this map we can use the annotation of write and we can say storage.mymap.insert with the number we've passed in and the on or off boolean if we want to get from the storage map we can use the annotation storage.read and then we can say storage.mymap.get with the letter n for the number that we've passed into the function so that's just a high level overview of the design of sway if you wanted to know more about the design and get into the details about we also also offer generics and

type inference enums structs if you're interested in learning more about that you can go to our website field.network and we have a swaybook there's also a we have several talks um coming up later today alex has a talk at what time at 5 40 uh across the hallway where he'll be talking about the advancements that sway has come from in the last year so that'll be exciting okay so now for the meat of what we'll be looking at in the workshop building our first contract so when we build our first contract we'll be building a contract that will

allow us to vote it'll allow a group of users to vote on what their favorite number is so you can think of it kind of like a dao where the dao is just voting on what the user's favorite number is um it'll be a little different from a dow it'll be a little limited and we'll see that in a second but you can think of it kind of like that so at a high level we'll be writing two different sway smart contracts that'll be interacting with each other one will be the governance token that'll be a very simple contract and the other one will be the actual voting contract that'll have the logic for adding governance tokens depositing them withdrawing them and voting we'll also be using fork to build and

test our contracts okay so if you're interested in doing this on your personal machine you can go to this website and download the repo and follow along there's like instructions for how to follow along in a skeleton code for how to implement it but it seems like a lot of people are on their phones so i'm wondering if it would be a good idea to ad lib some live code yeah okay i think i'm going to add live some live code which i've never done before so please bear with me uh and nor did i plan for this um but i'm really

hoping that i can give y'all a feel about what it's like to build with sway so i'm gonna set this down and start yelling okay so if we go to you know hear me yeah okay so if we go to this github uh it'll point us to yeah you need to keep closer oh i'm gonna be coding yeah when you talk for the recording okay is yeah

so i have to hold that and then okay so um yeah that should work i'll just talk loudly too yeah yeah okay okay

all okay so when you go to the uh github you'll come across this repo so uh you can either follow along now or you can follow along later but it has some resources in it that will help you get started so to start off with it all it has this cool readme with a description about what we're doing we're building this voting contract that allows us to vote on our favorite number it has some steps about how we can get started getting set up setting up our

editor the two contracts that we're writing that token contract that voting contract and then some ideas for how you can work on this contract going forward and expand it so it also has a skeleton project for to get you started where you can just fill in some functions and then it has a solution for you to check your your progress and today live we'll be filling in the skeleton project and doing it and discussing the display code together so i have this on my machine okay

okay so here's that exact repo that we saw on github uh but just in vs code to start out with we're going to build the token contract so this is our governance token that our users are going to use to vote in the in the contract so what they'll do is they'll use the governance token to deposit in the contract and then once they've deposited the tokens they can use those to vote or they can withdraw their governance tokens if they don't want to vote anymore starting out we'll go into our source directory that has our sway file and we see that in here we have a couple different items so

at the top of every contract in sway there's this contract declaration this is just telling the sway compiler that we're looking at a contract next we have our dependencies i won't dive too much into the module system and the dependency system that sway has but you can think of it as being very similar to the rest module system independency system if you're familiar with that could you speak a little bit yeah uh and then next we have our abi definition so this abi definition looks similar to the one that we saw in the slides it has one function so the avi is called my token with the function mint and send to address this function will mint the token and

send it to the address that we provided here we're implementing the the my token abi for contract and we have this skeleton code that we're going to be uh uh fixing uh so that we can actually mint it and send it to the address one of the uh so one of the uh benefits that sway provides you is that sway provides a very extensive standard library the standard library has a bunch of different data structures that allow you to to build your blockchain applications one of these and a bunch of different functions that

allow you to build these blockchain applications without having to you know reinvent the wheel we've we've done a lot of the heavy lifting for you and provided you with those building blocks already one of those is the function mint to address that's coming from the standard library so the mint to address function does what it says it means a token uh and then it sends it to the address that you've provided so we will call this function mid to address with the amount that we're passing into the abi function which is just called amount and then

in our to field we will pass in the recipient which is the recipient in the avi definition and that's it that's all we have to do to write a contract with a that mints tokens and send them to users okay uh hopefully this doesn't get confusing but here we have vs code and then when i flip over uh this is just the terminal with the same repo so now we're inside of that token contract that we just filled in and we're going to build this using fork we're going to call fork build

oops oh and see okay so we called for build fork build gave us a compiler error and this compiler error is giving us a message about what's wrong it's saying that it's an unexpected token in the statement and this state this error message is telling us that we're missing a semicolon uh right here so we can go back and add this semicolon save it and run for build again and we see that fork successfully builds this way project so that's all we have to do to build our first uh sway contract okay now we're going to build the contract that does the voting

[Music] yeah so my question is so this is just like a toy example um in in an actual example you would want to check to make sure that this returns result and then do something yes okay so

uh now we're gonna take a look oh and that please interrupt me if there's any questions uh if y'all are lost i really want this to be as interactive as possible so let me know if you have any questions okay so now that our token contract is done we're going to write our contract for voting our contract for voting has three different files it has our library file which has the api definition it has the error file which is going to help us do error handling and it has our main file which has the implemented abi definition for a contract so we're going to start out by looking at the avi definition first the api definition has several different functions

it has an initialized function a function that gets the balance of the contract a function that gets the balance of particular users it gets the current favorite number gets the number of votes for a particular number um it allows you to deposit coins uh allows you to withdraw or deposit tokens allows you to withdraw tokens allows you to vote and allows you to execute the voting schematic and count the votes and set a new favorite number so inside of this library we've also provided

like a sense of state so sway has structs and enums and here we see an example of an enum so an enum you can think of it like a sum type so in this enum state it's either like a non-initialized state or it's an initialized state and when you have a variable that's of type state you can check to say okay is my state not initialized or is it initialized and we're going to use this in our contract to check to see if we've run this initialized function here because the way that we're going to implement it we don't want to have users like voting if we haven't set up the

voting system yet and we'll see that in a second okay so there's a lot to talk about here um and we'll just go through it step by step at the top is our contract definition that we saw in the previous uh example then we have our dependencies and uh use statements again i'm not going to get too much into this dependency system but you can think of it similar to rust dependency system here we have a constant value this constant value will be used to determine the maximum value of

the possible favorite number so in this particular example the favorite numbers users can vote on are between 0 and 99 inclusive so they are not they're not able to vote on 100 but they can vote on zero to 99. yep the difference between just light and there was difference yeah uh const is a constant variable um so it's not able to be mutated and it has special properties inside of the compiler so for instance um it will be able to be sweet sway has match statements and it will be able to be used in a

match statement you will be able to match on a constant versus you will not be able to match on a dynamic value because a dynamic value will change yeah that's awesome also constants are global but let's are all scoped to the surrounding scope but the constant is always global yeah and so that's the difference between let's and let's mute right because you had let and let mute before yes so yes my question was mostly between constant light and that mute but then thanks okay we have our contract storage um

there's the state which is that initialized or not initialized value we're starting it off as non-initialized because we haven't initialized our contract we have our contract id of the governance token that's going to be used to allocate our votes yes do you have to annotate constants like in rust you have to say like the maximum is like a size or you know you want me to repeat it oh um do you have to annotate uh constants like you do in rust um so like uh in rust if it's a you know a number you would have to annotate it to be like

you size or e32 or whatever okay cool uh we're gonna keep track of our current favorite number in contract storage we're going to keep track of the current number of votes for each prospective favorite number and we're also going to keep track of the balance for each user so this is the number of governance tokens that they've deposited into the contract and here is where we're implementing that uh voting api from the previous file for this example before we get into implementing it i'm going to show you

how we're going to be thinking about this problem so if we go into the voting contract we can build it but we can also run tests so what i've done is i've already pre-written a couple tests for this project that are going to help us drive development and these tests yeah they all fail because none of our functions are implemented yet but these tests are going to help us think about the project and think about how we want to implement our functions so the tests are you know can we deploy and initialize the voting contract can multiple users vote can multiple

users vote and execute to find a new favorite number so as we're building today we will be seeing these tests start to pass i just want to check the time really quick okay okay so we're going to start out with and just implement the initialize function we have a couple to do's the first to do is we are going to set the storage uh token variable to the token that we passed into the contract and to do that we're going to use the storage dot syntax so we'll say storage dot token equals token and then number two is we're going to set the

storage state to initialize because we're calling the initialize function storage.state equals state initialized and then lastly we're going to insert values into the number into the storage.number votes from zero to max num using a while loop so i'll write that for us so we'll say let me i equals zero while i is less than max num i plus equal one and we'll say storage dot number votes insert i zero

so this will insert uh into our number of votes for every number it starts out with zero votes and we'll uh go ahead and run this so when we're running fork test fork test actually runs fork build under the hood before it runs the test so during this exercise i'm just going to be running fork test and just know that it's running fork build under the head for us okay so we can see here that uh one of our tests passed well actually two of our tests pass so the tests that pass are the deployer can initialize the voting contract which is good because we just wrote the initialize function and we also see that

the deployer can mint function pass which is good because in our previous contract the token contract we wrote that function that calls mint to address so what this is saying is right now we're able to mint our governance tokens and we're able to initialize the voting contract i see a while loop over here do you guys support any sort of for loops it's on the roadmap but we don't currently have them in the language thank you okay so

uh here we have some getter functions so we can get the current balance of the contract this is a standard library function that gets the balance with the token that we pass in so this will just get the contract balance of the governance token this is a getter function which will get the balance of a particular user so here we have another standard library function called message.center message.sender will return the identity of the user or the contract or the address that's called the contract that we're in right now so in our tests when we run fork test we can think of these like users with

wallets and people that are executing this contract and when when they're executing this contract the message.sender function from the standard library is retrieving their identity and it's allowing us to create a unique user for them you can think of it like a b256 value and it's allowing us to create that unique user and insert their unique user value into the user balances storage map importantly message.sender returns like a special result type which you can think of as a special error type so in order to handle this special error type it needs an

accompanying function called unwrap which allows us to access that identity another get function which allows us to get the current favorite number oh thank you great yeah thank you

okay time to implement another function so now we're going to implement the deposit oh my gosh okay now we're going to implement the deposit function uh this function is going to allow users to deposit governance tokens into the contract then with those tokens they'll vote for their new favorite number so there's a lot of to-dos here but we'll take them one at a time so the first to do is get the identity of the user that called the contract with the function using the message sender function from the standard library we actually saw that up here in our get user balances

so for the purposes of this we'll just copy this and we'll say okay we're going to get our user with the standard library function message center and we're going to unwrap that to retrieve the identity then we're going to get the amount of the deposit with the function message amount so we'll say our amount equals the message amount then we will get the previous balance of the user from our storage.user balances so we'll say our previous balance equals our storage dot userbalances.get and we'll pass in the user this is because

we've been indexing our user balances with this user identity next we will calculate the new balance using the values from step two and step three so we'll say our new balance equals our previous balance plus the amount that we're depositing and lastly we'll update the user balance using the storage dot userbalances.insert we'll so we'll say storage dot user balances dot insert with the user and the new balance okay so this is great but there are a couple

things to consider so one what if the user tries to deposit a token that's not our governance token well they should probably not be allowed to do that or what if they tried to deposit zero tokens well they should probably not be allowed to do that either in order to accommodate these cases sway provides some error handling methods in this particular example we see an instance of the error handling method here called require require takes two arguments it takes a conditional and a value and it says okay i want to require this conditional to be true

and then if it's not true i'm going to revert with this value so at the beginning of each of these functions i've already provided that i want to require that the state is initialized and if it's not all initialized i'm going to return this error that the contract is not initialized but we could expand on this and say you know i want to require that the amount that the user is depositing is above zero and if it's not above zero i want to return an error saying that the value is not above zero or i want to require that the user is depositing the correct governance token just so that we can speed up the example i'm not going to go into that but just know that you could do that in your own time later if you if you wanted to

okay so now we're going to run the test again and see if we've successfully written the deposit function cool okay so we can see that the user can deposit which is great that means we've written the deposit function successfully i'm just going to check the time again okay all right now we're going to write a function that will allow the users to withdraw governance tokens again there's a couple to do's but we'll go through them one by one so the first one get the identity of the user we know how to do this from the previous one so i'll just copy this look at the identity of the previous of

the user uh get the previous balance of the user from storage.userbalances so we'll say let the previous balance equals storage.userbalances.getuser step 3 calculate the new balance using the values from step 2 and the amount to be withdrawn so we'll say let the new balance equals the previous balance minus the amount to be withdrawn update the user balance using the user balances insert so we'll say storage dot user balances dot insert giving it the user and the new balance and then we'll transfer the asset that

we're withdrawing back to the user using the transfer function from the standard library and the way that we're going to do that is we're going to use this function transfer we're going to pass it the amount we're going to pass it the asset id which is the storage.token which is our governance token and we're going to pass it the user that we've retrieved which is just user yes so does the transfer function which currently has a typo is uh is that transferring a token from one contract to another yes yeah

so in ethereum and solidityland this usually requires an initial approve and then something like a transfer from this appears to not require an approval is that an intentional design choice yes could you could you expand on that if you could um so i mean from a design perspective a lot of the design decisions of sway are are made for ease of use and and developer experience so by providing much of the standard library by providing the way that we've designed the fuel vm um much of the

much of the components that wrap a transfer that you would need to do in solidity are just kind of uh put as guarantees in the compiler underneath the hood so there's and and when i'm saying that it's it's a broad spectrum way of saying some of the things that you would be used to seeing in solidity are things that are allocated to the standard library but they're also some of the things that are guarantees by product of the design of the fuel vm

and that's manifesting in the fact that to transfer an asset you simply have to call the transfer function okay so again uh what if the user wants to withdraw more governance tokens than they've deposited we certainly don't want them to do that and to prevent them from doing that we would write a require statement to require that their previous balance is the same or greater than the amount that they want to withdraw but for the purposes of this exercise we're not going to do that we're just going to trust that all of our users are good actors and they don't withdraw too many tokens so we'll test this with fork test

and we see that users can deposit and withdraw which is great check my time okay so we have about 10 minutes left so we have time for one more function and then i'll just wrap it up for questions so the last function that we'll write is vote um and for vote the users will take their deposited governance tokens and they'll allocate them to the number that they want to vote for okay oops so first thing we do is get the user which we've done before so we'll just copy this okay get the previous balance of the

user so we'll say like previous balance equals storage dot oops [Music] user balances dot get with the user okay calculate the new years of balance using the value from step two and the vote amount so we'll say the new balance equals the previous balance minus the vote amount because the user is spending their tokens to vote update the user balance using the new amount so we'll say storage dot user balances dot insert with the user and the new

balance okay now we're going to get the current number of votes for the number that the user is voting for using the storage dot number of votes so we'll say current votes equals storage dot number votes with get and the voting for number argument then we'll calculate the new number of votes so we'll say new votes equals current votes plus vote amount and then we will update the number of votes to our new number of votes so this will be our storage dot number of votes insert uh with our voting for number

oops and our new votes okay so this is taking the uh amount that the user is passing in that they want to allocate towards a vote and the number that they want to vote for it's retrieving those tokens from the user's balance and allocating them towards the number that they want to vote for again we should consider when they don't have enough tokens if their balance is not high enough but in this example we will bypass that so let's test this and we see that a bunch more tests pass because now users can vote

so the users can vote test pass multiple users can vote and users can vote for multiple numbers all pass so the tests that are still failing are the tests that require us to execute uh the votes and update the current favorite number unfortunately we don't have time for that today because i want to wrap up with some concluding statements but hopefully i've piqued your interest enough to where you can finish that last function on your own okay so today we covered what is sway it's a language for building smart contracts on the fuel ecosystem and the fuel virtual machine we talked about how to get started with

sway and fork and we wrote our first smart contract in sway to wrap up i want to plug our new grant program that we have available so fuel is running this grant program if you're interested in using sway using fork and learning more about fuel you can apply applications are open right now we have anywhere from 10 to 150 usd available we are excited for people to get interested and get moving with with sway and and start developing thank you all so much there's qr codes

so the one on the left is the form for the grant and the one on the right is the twitter i'm happy to answer any questions if anybody wants any more resources please let me know thank you all so much [Applause]