banner

When I first started working here at Run, I spent my time developing some examples using Node and React along with Run to help me ramp up a little.

Since I’m new to the crypto world in general, and in Run in particular, I thought it could be a good idea to share a couple of things I’ve been learning that might be interesting for every developer like me, that has experience building traditional apps and wants to start playing around with Jigs in Run.

Thinking in Jigs

Remember Jigs? One of the main tools Run offers which encapsulate all the necessary logic to get objects stored in the blockchain.

Given that Jigs look a lot like normal JS classes (well, in fact they are), one tends to create abstractions as we normally do, and that’s kind of the deal with Run.

But there are a couple of implications that comes with the fact of having objects stored in the blockchain that changes the way we should be thinking about Jig abstractions.

A case study

Let’s see an example that taught me a couple of lessons.

Suppose that we have a crafting game, so we have items that can be crafted depending on a recipe. If the user has enough of every needed ingredient, the item gets created and added to users inventory. If not, an exception is thrown.

So, let’s discuss this possible approach:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class Recipe extends Run.Jig {

init(ingredients, resultItemClass) {
this.ingredients = ingredients
this.resultItemClass = resultItemClass
}

craftFor(user) {
if(!this.canCraftMe(user)) throw new Error ('The user does not have enough ingredients')

// these methods obviously update the user jig state
user.burnIngredients(this.ingredients)
user.addToInventory(new this.resultItemClass())
}

canCraftMe(user) {
return this.ingredients.every(ingredient => user.hasEnough(ingredient))
}
}

This approach has several problems and we are going to use it to explain a couple of things.

Jigs Ownership

Ownership is not a new concept for traditional devs. We’re used to thinking about users, groups, permissions, etc.:.

With Jigs, ownership is a first class citizen concept. All jigs come right from the bat with an owner field as explained here.

Jigs can only be updated directly by the same owner. So if a jig is trying to update another one, they must either belong to the same owner, or require an explicit process in which the other owner allows the update to take place (by requiring them to sign a tx).

That means, that when in Recipes code we do:

1
2
user.burnIngredients(this.ingredients) 
user.addToInventory(new this.resultItemClass())

we are going to receive an error if the recipe and user owners are different (which in this case is possible as users may want to craft items from recipes not owned by themselves)

Take a moment to pause here just 5’ and think about how would you work around this limitation. I’m going to explain another problem of this approach and then propose an alternative that fixes both.

Jigs Creation

The fact that your code is in the blockchain means that your code is public and ready to be executed by anyone. We are used to having the monopoly on our code execution, but here, anyone can instantiate our classes and do whatever with them.

Let’s use the same example to explain this a little better.

If I publish my Recipe, User, and Item jig classes, anyone can instantiate objects from them. That means anyone could execute something like:

1
2
3
4
5
6
7
8
9
10
11
12
// previously existing class
class Item extends Run.Jig {
init(name, quantity) {
this.name = name
this.quantity = quantity
}
...
}


// anyone else's code
const superRareAndExpensiveItem = new Item('Gold', 1000)

and suddenly have lots of gold in their game inventory. How can we prevent this?

Let’s see a possible solution

Ok… what do we need to solve?

  • I need to update the user state from a jig that belongs to the same owner
  • I need to make Items instantiation stricter in order to prevent anyone creating Items at will
1
2
3
4
5
6
7
8
9
10
11
12
13
class Item extends Run.Jig {

init(recipe, user){
this.validateUserHasIngredients(recipe, user);
this.name = recipe.itemName;

....

this.owner = user.owner;
user.burnIngredients(recipe.ingredients);
}
}

So, why this works? I needed to solve two things:

  • I needed to be able to update users state if they’re able to craft an item. So given that the item is going to belong to the user as soon as it is confirmed it can be crafted, the user is going to be updated by a Jig that already belongs to the same owner
  • I needed to guarantee that Items can get instantiated only if someone has the right amount of ingredients. So here, you cannot execute new Item() and call it a day. You have to specify a Recipe and no Items will be created until all necessary validations pass and a price in Ingredients is paid. In this example we manage to solve the instantiation problem by using plain JS and our domain rules, but Run also offers builtin tools for validating our Jigs instantiations. This process is call minting and we’ll definitely cover this further into this blogspot series about Run for Js devs.

Wrapping up

So, the lesson for today is that even tough Jigs are a great tool for developing blockchain related apps, the fact that our code gets published on chain has multiple implications that must be dealt with, and that affects the way we design our abstractions.

And that’s it for now!

Stay tuned for more posts about Run for JS devs!