encode
Creates a transaction according to the Bitcoin Computer protocol.
Type
;(opts: {
exp: string // an expression
env?: Record<string, string> // a blockchain environment
mod?: string // a module specifier
// Funding options
fund?: boolean // whether to fund the transaction
include?: string[] // include specific UTXOs when funding
exclude?: string[] // exclude specific UTXOs when funding
// Signing options
sign?: boolean // whether to sign the transaction
sighashType?: number // signature hash type to use
inputIndex?: number // input index to be signed
inputScript?: Buffer // use input script (instead of signing)
// Mock options
mocks?: Record<string, any> // values to mock
}) =>
Promise<{
// the transaction with the expression inscribed
tx: NakamotoJS.Transaction
// the result of the evaluation
effect: { res: unknown; env: { [s: string]: unknown } }
}>
Parameters
opts
An object with a specification to build a transaction according to the Bitcoin Computer protocol.
Return Value
It returns an object { tx, effect } where tx is a NakamotoJS transaction and effect is an object with keys res and env. The res object contains the result of the evaluation. The env object has the same keys as the blockchain environment. However, whereas the values of the blockchain environment are revision strings, the values of env and the smart object at these revisions after evaluating the expression.
Description
The encode function builds a Bitcoin transaction from a JavaScript expression. It returns a transaction and an object effect containing the result of the evaluation in a property res. If the expression contains undefined variables a blockchain environment env must be passed into encode. A blockchain environment maps the named of the undefined variable to UTXOs containing on-chain objects. A module specifier can be provided in order to make the exports of that module are available to the evaluation.
When a module specifier mod is supplied to encode, all objects that are created in the transaction are associated with that module specifier. The module specifier never changes, even when the object it updated. It is important to note that if an object o1 created a second object o2 in a method call, o2 does not automatically inherit o1's module specifier. If this is desired, then module specifier needs to be passe into the expression encoding the function call. For example, the transfer function of the TBC20 contract creates a new object for the receipient. This object will not inherit the module specifier of the original token. If this is desired the module specifier needs to be passed into the encode call of the transfer function.
Other options can customize the funding and signing process. It is also possible to pass in an object specifying mocked objects.
It is important to note that encode does not broadcast the transaction. Nonetheless the effect object reflects the on-chain state that will emerge once the transaction is broadcast.
The state update effected by a Bitcoin Computer transaction is completely predictable:
- If the transaction is included in a block the new state will be exactly the state returned from the
effectfunction. - If the transaction is not included the state is not updated.
Example
import { Computer, SmartContract, Contract } from '@bitcoin-computer/lib'
import { chain, expect, network, url } from '../../utils/index.js'
describe('encode', () => {
let computer: Computer
before('Create and fund wallet', async () => {
computer = new Computer({ chain, network, url })
await computer.faucet(1e8)
})
// Objects
it('Should work for a class', async () => {
// A smart contract
class Counter extends Contract {
n: number
constructor() {
super({ n: 0 })
}
inc() {
this.n += 1
}
}
// Encode a constructor cal
const { effect: e1, tx: tx1 } = await computer.encode({
exp: `${Counter} new Counter()`,
})
// Broadcast the transaction
const txId1 = await computer.broadcast(tx1!)
// As above, synchronizing to a transaction id always returns the effect
expect(await computer.sync(txId1)).deep.eq(e1)
// The result of effect e1 is a counter
const counter = e1.res as SmartContract
// Encode a function call incrementing the counter
const { effect: e2, tx: tx2 } = await computer.encode({
// The expression
exp: `c.inc()`,
// The value for the counter is stored at counter._rev
env: { c: counter._rev },
})
// As before we can broadcast the transaction to update the on-chain state
const txId2 = await computer.broadcast(tx2!)
// The sync function reads the on-chain state
expect(await computer.sync(txId2)).deep.eq(e2)
})
})