Jigs

From RunWiki
Revision as of 22:08, 28 April 2023 by Zhell (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Jigs are interactive objects on Bitcoin. You define a jig with a JavaScript class and that class determines exactly what the jig can do. All of your jigs are unique. Each one has an owner and only that owner can update the jig. How is that secured? Bitcoin! Let's explore how you create a jig.

Creating

Let's create a new class of jigs called Post to represent comments on a message board. In JavaScript, your class initializer is called constructor, but for jigs, this method is called init. Think of them the same way. If init throws an exception, the jig will never be created, just like constructors. You create jigs with the new keyword, just as you would with normal JavaScript objects, and they get deployed onto the Bitcoin network. Pretty cool.

Code

class Post extends Jig { 
    init(message) {
        this.message = message
    }
}

new Post('Hello, world')

Updating

Jigs are updated by calling methods. In fact, this is the only way to update jigs. Your jig class defines the ways that your jig instances may evolve, so be sure to think ahead. When you call a method, Run publishes a Bitcoin transaction with data in an op_return that includes the method name and its arguments. The state may be recomputed simply by playing back every update one-by-one. For more information about how it works, see How It Works.

Code

class EditablePost extends Post {
    edit(message) {
        this.message = message
    }
}

const editablePost = new EditablePost('Hello, world')

editablePost.edit('Hello, BitCoin')

Sending

Jigs may be sent to someone else by changing the owner property of a jig in a method. You can set the owner to a Bitcoin address, a public key, or a custom Lock. The new owner will be able to update the jig starting in the next transaction.

Code

class Dragon extends Jig {
  send(to) {
    this.owner = to
  }
}

new Dragon().send(address)

Syncing

Run is asynchronous. When you create or update jigs, Run creates Bitcoin transactions for you in the background and broadcasts them to the network. As with any network request, the request may sometimes fail. Your connection may go down, or a node on the network may reject your transaction.

Every jig has sync() available to ensure your local state is the same as that on the network. Calling await jig.sync() returns when:

All pending local transactions have been published successfully, and The jig has been caught up with any new transactions from the network. Any errors in validation or network requests will throw an error.

When testing ideas out in the browser, you won't need to call sync() very much. Run will happily execute method calls on jigs in their latest state. However, in a production app, the best practice is to call sync() after every method call to ensure that you catch errors early and handle them gracefully. Calling sync() will force any error to show up at that particular line in the code.

Run updates your jig's state with each method call you make. However, it does not continuously update your jigs with the blockchain. Because if it did, as a developer you'd feel like you were on shifting sand. Instead, you've got a reliable and steady state for each jig that you're working with. Therefore, depending on the app you've built and actions of the owner of the jig, you might need to catch up a jig to its latest state because it could have been modified outside of your app.

Code

Wait for updates to complete

class LoyaltyCard extends Jig {
    init() { this.stamps = 0 }
    stamp() { this.stamps +=1 }
}

const card = new LoyaltyCard()
await card.sync()

card.stamp()
await card.sync()

Sync a jig from its origin to its latest state

const card2 = await run.load(card.origin)

await card2.sync()



Checking Parameters

You should always check the parameters passed to your methods. If you are expecting a number, make sure it is really a number. If you are expecting a jig, then make sure you have a jig of the right class. This prevents others from mis-using your jigs.

For your convenience, Run provides the expect sidekick. expect lets you make assertions similar to those you might be familiar with in Jest or Chai. You can to check many things, including if a jig is a certain class, if a number is greater than another number, or if a parameter is of a certain type. To get started, add expect as a dependency to your jig class. Then, check out the expect documention to find the right assertion.

Sometimes you may wish to check if a class is part of a changing set. For example, a game may have a list of item classes that may change over time. This is a little more advanced. See the Dynamic Whitelists section.

Code

Attaching an item

class Hat extends Jig { }

class Person extends Jig {
  wear(item) {
    expect(item).toBeInstanceOf(Hat)

    this.item = item
  }
}

Person.deps = { Hat, expect: Run.extra.expect }


Now that you understand the basics of jigs, let's see how to use them with more advanced actions like Interactivity, Destroying, Backing or attaching media at Jigs (advanced)