Skip to main content

Using the Schema Tool

We tried to make the creation of smart contracts as simple as possible. The Schema Tool will assist you along the way as unobtrusively as possible. This section will walk you through the steps to create a new smart contract from scratch.

First, you need to decide on a central folder where you want to keep all your smart contracts. Each smart contract you create will be maintained in a separate subfolder of this folder. We will use certain naming conventions that the schema tool expects throughout this section. First we will select a capitalized camel case name for our smart contract. For our example, MySmartContract.

Once you know what your smart contract will be named, it is time to set up your subfolder. Simply navigate to the central smart contract folder, and run the schema tool's initialization function:

schema -init MySmartContract

This command will create a subfolder named mysmartcontract and generate an initial YAML schema definition file inside this subfolder. Note that the generated subfolder name is all lower case. This is to conform to best practices for package names in most languages. The generated schema definition file looks like this:

name: MySmartContract
description: MySmartContract description
events: {}
structs: {}
typedefs: {}
state:
owner: AgentID // current owner of this smart contract
funcs:
init:
params:
owner: AgentID? // optional owner of this smart contract
setOwner:
access: owner // current owner of this smart contract
params:
owner: AgentID // new owner of this smart contract
views:
getOwner:
results:
owner: AgentID // current owner of this smart contract

The schema definition file has been pre-populated with all sections that you could need, and some functions that allow you to maintain the ownership of the smart contract. Now that the schema definition file exists, it is up to you to modify it further to reflect the requirements of your smart contract.

You should use camel case naming convention throughout the schema definition file when naming items. Function and variable names always start with a lower case character, and type names always start with an upper case character.

The first thing you may want to do is to modify the description field to something more sensible. And if you already know how to use the schema tool, then now is the moment to fill out some sections with the definitions you know you will need.

The next step is to navigate into the new mysmartcontract subfolder and run the schema tool there to generate the initial code for the desired language:

If you want to generate Go code, you should run the schema tool with the -go option like this:

schema -go

If you want to generate more than one language your can simply specify multiple options. For example, to generate both Rust and Go code you would specify both options like this:

schema -rs -go

The schema tool will generate a complete set of source files for the desired language(s), that will compile successfully into a Wasm code file. You compile these as follows:

tinygo build -target wasm go/main.go

This will use the Go source files in the go/mysmartcontract subfolder. The only file in this folder that you should edit manually is mysmartcontract.go. All other source files will be regenerated and overwritten whenever the schema tool is run again.

See the TinyGo documentation for more build options.

The generated code is essentially identical for each language, barring some language idiosyncrasy differences. Just view different language files with the same name next to, each other, and you will see what we mean.

Here is an example of the initially generated code, mysmartcontract.xx looks like this before you even start modifying it:

package mysmartcontract

import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib"


func funcInit(ctx wasmlib.ScFuncContext, f *InitContext) {
if f.Params.Owner().Exists() {
f.State.Owner().SetValue(f.Params.Owner().Value())
return
}
f.State.Owner().SetValue(ctx.RequestSender())
}

func funcSetOwner(ctx wasmlib.ScFuncContext, f *SetOwnerContext) {
f.State.Owner().SetValue(f.Params.Owner().Value())
}

func viewGetOwner(ctx wasmlib.ScViewContext, f *GetOwnerContext) {
f.Results.Owner().SetValue(f.State.Owner().Value())
}

As you can see the schema tool even generated an initial working version of the functions that are used to maintain the smart contract owner that will suffice for most cases.

For a smooth building experience it is a good idea to set up a build rule in your build environment that runs the schema tool with the required parameters whenever the schema definition file changes. That way regeneration of files is automatic, and you no longer have to start the schema tool manually each time after changing the schema definition file. The schema tool will only regenerate the code when it finds that the schema definition file has been modified since the last time it generated the code. You can force the schema tool to regenerate all code by adding the -force flag to its command line parameter.

In the next section we will look at how a smart contract can access its associated storage by using Data Access Proxies.

Video Tutorial

Creating Smart Contracts using AssemblyScript