#
Smart Contract Language
The Bitcoin Computer uses Javascript with slight modifications. Specifically:
- Property assignments are not permitted outside function calls. This makes it possible to impose constraints on all future values of an object, thereby making Javascript a viable smart contract language
- Certain keyword properties have a special semantics. This gives the smart contract programmer fine grained control over the transaction being built.
- Assignments to
this
is not permitted in constructor calls. This is necessary for internal reasons to ensure the first two properties.
These properties are technically enforced by the requirement that all objects returned from a smart contract inherit from a class Contract
that is exported from the Bitcoin Computer Library.
In the following we explain the three properties in detail.
#
Assigning Properties Outside of Function Calls is Prohibited
Assigning to a property outside of a function call throws an error.
This makes it possible to write classes that impose constraints on all future values of an object. Consider for example the class Even
below. The condition guarantees that all instances of the class will always have an even value.
class Even extends Contract {
inc2() {
this.n = (this.n || 0) + 2
}
}
const even = new Even()
Calling even.inc2()
works as expected.
even.inc2()
expect(even.n).eq(2)
However, assigning to even.n
outside of a function call throws an error.
try {
even.n = 3
expect(true).eq(false)
} catch(err) {
expect(err.message).eq("Cannot set property 'n' directly")
}
While this is not a very useful example for a constraint, all smart contracts are based on constraints to future values in a similar way.
#
Special Semantics of Keyword Properties
The Bitcoin Computer uses special properties (called keyword properties) that
- control details of the transaction being build, and
- give the user information as to where on the blockchain a smart object was created and where it is currently stored.
type SmartObject = OutputDetails & Location
In the following we describe these properties in details
#
Control Keyword Properties
Properties named _amount
, _owners
, _readers
, and _url
provide control over the transaction being built. These properties can optionally be set in the smart contract.
type OutputDetails = {
// determines which users can update the object
_owners?: string[]
// determines number of Satoshis stored in the output associated with the object
_amount?: number
// determines whether object is encrypted and who can decrypt it
_readers?: string[]
// determines if data is stored off-chain
_url?: string
}
The effect that these properties have on the transaction being built is described below:
- If a property
_amount
is set it needs to be set to a number. It determines the amount of Satoshi stored in the output representing the current revision. If it is not set the revision will have a minimal (non-dust) amount of Satoshi. - If a property
_owners
is set it needs to be set to an array of strings [p_1\ ...\ p_n]. These determine the output script of the current revision. Specifically, the script for the current revision is a 1-of-n multisig script with the public keys p_1\ ...\ p_n. This guarantees that only a user that has a private key corresponding to one of the public keys can update the object. If the property is not set it defaults to the public key of the computer that created the object. - If a property
_readers
is set it needs to be set to an array of strings [p_1\ ...\ p_n]. If this property is set the meta data in the corresponding transaction is encrypted such that only users with corresponding private keys can decrypt the expression and compute the value of the smart object. If the_readers
property is not set the meta data is not encrypted and any user can compute the value of the smart object. - If a property
_url
is set it needs to be set to the url of a Bitcoin Computer node. If it is set the expression is not stored in the transaction but on the node instead. The transaction only contains a hash of the expression and the location where the expression can be obtained from the node. This is convenient if the expression is large, for example because it contains a lot of data.
#
Location Keyword Properties
The properties _id
, _rev
, _root
contain information about where a smart object was created and where it is currently stored. These properties are set by the runtime. While they can be read, attempts to overwrite their state will lead to an error.
type Location = {
// output where object was created
readonly _id: string
// output where object is currently stored
readonly _rev: string
// useful for building fungible tokens
readonly _root: string
}
- The value of the
_id
property is the output (encoded as <transaction id>:<output index>) that represented the object immediately after it was created. - The value of the
_rev
property is the output of the currently representing the object (that is, the object's revision). - The value of the
_root
property is assigned once when the object is created and is never modified subsequently. If the expression that creates the object is of the formnew C(...)
then its root is equal to its id. If the expression is of the formx.f(...)
then the root of the new object is equal to the id ofx
. Otherwise the root is set ton/a
. The root property is useful for building fungible tokens.
#
Assigning to this
in Constructors is Prohibited
In order to enforce the properties above, it is currently not permitted to assign to this
in constructor calls. Instead, an initialization object can be passed into the constructor:
class A extends Contract {
constructor() {
super({ k1: v1, ... kn: vn })
}
}
This has the same effect as setting assigning to this
in a normal Javascript program
// Not a smart contract, for illustration purposes only
class A {
constructor() {
this.k1 = v1
...
this.kn = vn
}
}