The first step is to create an object computer
from the Bitcoin Computer npm package.
import { Computer } from 'bitcoin-computer'const computer = new Computer({seed, // a bip39 mnemonicchain, // 'BSV' or 'BCH'network, // 'livenet' or 'testnet'wocApiKey, // a woc api key (optional)path = "m/44'/0'/0'/0", // a bip 32 path})
You can generate a fresh BIP39 seed phrase using a seed phrase generator. If no seed phrase is passed in a random Bitcoin wallet is generated.
A smart contract is a Javascript class.
A smart contractclass Counter {constructor(n) {this.n = n}inc() {this.n += 1}}
The new()
method creates a smart object from a Javascript class and an array of arguments for the constructor.
Deploying a smart objectconst counter = await computer.new(Counter, [2])
Every smart object has a property _id
that is set to the output on the Bitcoin blockchain that records the creation of the smart object. This id remains fixed throughout the lifecycle of the object.
A smart object can be updated by calling one of its functions.
When a smart object is updated a transaction is broadcast that records the state change. It is therefore necessary to await
on function calls.
To update the counter
smart object created above, we can call its inc
function.
await counter.inc()
When a smart object is updated a new output is created on the blockchain that stores the new revision. The property counter._rev
.is always set to the output that stores the latest revision.
The computer.sync()
method returns the smart object stored at a given location. This allows one user to create a smart object, send the id of the smart object to another user, and the second user can synchronize to the same object. For example a user Alice could run the following code
Code run on Alice's local computerimport { Computer } from 'bitcoin-computer'const computerA = new Computer({ seed: 'seed phrase of Alice' })const counterA = await computerA.new(Counter, [2])console.log(counterA._rev)// logs 'ac445f8aa0e6503cf2e...03cf2e:0'
Next, Alice sends the revision 'ac445f8aa0e6503cf2e...03cf2e:0' to her friend Bob. Bob can create an instance of the same smart object on his local machine.
Code run on Bob's local computerimport { Computer } from 'bitcoin-computer'const computerB = new Computer({ seed: 'seed phrase of Bob'})const revision = 'ac445f8aa0e6503cf2e...03cf2e:0'const counterB = await computerB.sync(revision)
At this point, both Alice and Bob both have a local instance of the same smart object. Additionally, there is an instance of the counter object that is stored in the blockchain. The instances are synchronized so that if Alice calls a function on her smart object the instance on Bob's local computer updates automatically. Consider, for example, that Alice calls the inc
function on her local machine:
Code run on Alice's local computerawait counterA.inc()
The object on Alice's computer updates the counter to 1
. Next, the update is recorded on the blockchain in a transaction. Finally, the instance on Bob's computer updates to the value 1
.
Code run on Bob's local computerconsole.log(counterB.n)// logs 1
Smart objects create the illusion that both Alice and Bob have access to the same local machine when in reality, they could be at different ends of the planet. In this sense, the Bitcoin Computer is the one global computer that we can all use together.
Bitcoin Computer adds two features to Javascript: Data ownership and storing cryptocurrency. These features are discussed in the following sections.
Every smart object has a property _owners
that can be set a list of public key strings. A smart object can only be updated by a user whose public key is in the _owners
array. Specifically, a smart object can only be updated if it was created by a computer instance (either by computer.new
or computer.sync
) that contains a mnemonic that corresponds to a public key in the current _owners
property.
The _owners
property can be set in a constructor call and updated in a function call. If no _owners
property is specified, it defaults to a singleton array containing the public key of the current computer
object.
In the example above Alice can call the inc
function but Bob cannot:
Code run on Bob's local computerawait counterA.inc()// worksawait counterB.inc()// throws an error> Communication Error> status 400 Bad Request> message 16: mandatory-script-verify-flag-failed> (Operation not valid with the current stack size). Code:-26
The next example shows how the _owners
property can be assigned in construction and function calls.
A smart contractclass OwnedCounter {constructor(n, pKey) {this.n = nthis._owners = [pKey]}inc(pKey) {this.n += 1this._owners = [pKey]}}
A smart object can store an amount of Bitcoin. The amount of Bitcoin, denominated in satoshi, is set through the _amount
property. The Bitcoin is owned by the owners of the object, and each owner can send the Bitcoin to another user (like themselves).
As an example consider the class Wallet
below.
class Wallet {constructor(amount) {this._amount = amount}send(amount, to) {this._amount = amountthis._owners = [to]}}
The following example shows how a wallet storing 30000 satoshi is created. The satoshi are taken out of the wallet of the computer
object. If a function call reduces the amount of satoshi in an object the remaining satoshi (minus miner fee) are returned to the wallet in the computer
object. The example also shows how the wallet can send Bitcoin.
import { Computer } from 'bitcoin-computer'// create Bitcoin Computer instancesconst computerA = new Computer({ seed: 'seed phrase of Alice'})const computerB = new Computer({ seed: 'seed phrase of Bob'})const wallet = await computerA.new(Wallet, [30000])const pKeyB = computerB.db.wallet.getPublicKey().toString()await wallet.send(20000, pKeyB)
When the function call is executed, the _owners
property of the smart object is updated to pKeyB
so that subsequently only Bob owns the output containing the 20000 satoshi.