deploy
Stores a Javascript module on the blockchain.
Type
;(module: string) => Promise<string>
Parameters
module
A string encoding a JavaScript module.
Return Value
A string of the form <transaction-id>:<output number> encoding the location where the module is stored.
Description
The deploy function stores a JavaScript module on the blockchain and returns a module specifier that identifier that module. This specifier can be passed into computer.new, computer.encode, computer.encodeNew, and computer.encodeCall as an optional parameter. In this case, the names exported from the module are available in the evaluation of these functions.
The rationale for deploying modules is to minimize on-chain data (and thereby the technical on-chain storage costs / hygiene dust): a module can be deployed once (preferably via taproot) and then referenced to create or update many smart objects using tiny expressions. This keeps using transactions small. This is unlike on-chain objects whose associated data is tied to a single use/revision. See the Fees "User Choices..." section for full minimization guidance.
The protocol supports two module storage types:
multisig- A module is stored in one transaction with several outputs that contain a bare multisig script each. These outputs are currently un-spendable (in a future update we will make them spendable). The maximum module size is about 18 kB; larger modules must be split into chunks of less than 18 kB and recombined in another module. Module encoding transactions usingmultisiggenerate hygiene dust outputs (see Fees for scope and costs).taproot- A module is stored in two transactions: one commits to the hash of the data on a taproot output script, and the second spends that output and contains the entire module in its input. These modules can be close to 400 kB or even close to 4 MB (if you know a miner that will include them). In addition, module storage is 4x cheaper due to the SegWit discount. Crucially, taproot module encoding transactions generate no hygiene dust outputs.
To select the module storage type, pass either multisig or taproot into the property moduleStorageType of the Computer constructor. If moduleStorageType is not specified, it will use taproot if available and multisig otherwise. For minimization of on-chain data and hygiene dust (and the UX trade-offs of single-tx vs. two-tx), see the Fees documentation, especially "User Choices to Control On-Chain Data and Hygiene Dust Costs" and the bare-multisig rationale (single-tx direct data for high-throughput reliability).
* Bitcoin Computer support coming soon
Examples
import { Computer } from '@bitcoin-computer/lib'
import { chain, expect, network, url } from '../../utils/index.js'
describe('deploy', () => {
let computer: Computer
before('Create and fund wallet', async () => {
computer = new Computer({ chain, network, url })
await computer.faucet(1e8)
})
// Modules stored in multisig scripts
it('Should deploy a module using multisig', async () => {
const multisigComputer = new Computer({
chain,
network,
url,
moduleStorageType: 'multisig',
satPerByte: 4,
})
await multisigComputer.faucet(1881764) // 1.9M sats
const big = `x`.repeat(12155) // ~ 12KB ==>> Each stored byte costs 157 satoshis aprox
const rev = await multisigComputer.deploy(big)
expect(rev).to.not.equal(undefined)
})
// Modules stored in taproot scripts
it('Should deploy a module using taproot', async () => {
if (chain && ['BTC', 'LTC'].includes(chain)) {
const taprootComputer = new Computer({ chain, network, url, moduleStorageType: 'taproot' })
await taprootComputer.faucet(436000)
const veryBig = `x`.repeat(396000) // ~ 400KB
const rev = await taprootComputer.deploy(veryBig)
expect(rev).to.not.equal(undefined)
}
})
// Modules that depends on one another
it('Should deploy a module that depends on another module', async () => {
const modSpecA = await computer.deploy(`export class A extends Contract {}`)
const modSpecB = await computer.deploy(`
import { A } from '${modSpecA}'
export class B extends A {}
`)
const { tx } = await computer.encode({ exp: `new B()`, mod: modSpecB })
expect(tx!.getId()).to.be.a.string
})
// Modules of arbitrary size
it('Should deploy a module of arbitrary length', async () => {
// Inputs a long string and outputs a module specifier where it can be obtained
const store = async (s: string, n: number) => {
// Partition the long string into chunks of size n
const chunks = []
for (let i = 0; i < s.length; i += n) {
chunks.push(s.slice(i, i + n))
}
// Deploy chunks and build recombining module
let module = ''
for (let i = 0; i < s.length / n; i += 1) {
// Deploy a chunk
const mod = await computer.deploy(`export const c${i} = '${chunks[i]}'`)
// Import chunk into recombining module
module += `import { c${i} } from '${mod}'\n`
}
// Export concatenation of chunks
const cs = Array.from({ length: n + 1 }, (_, i) => `c${i}`).join(' + ')
module += `export const s = ${cs}`
// Deploy recombining module
return computer.deploy(module)
}
// Create a long string, could be hundreds MB in a real example
const longString = '0'.repeat(10)
// Store long string, you can use 18262 instead of 3 for multisig modules
// or 396000 for taproot modules
const mod = await store(longString, 3)
// Load a long string
const { s } = await computer.load(mod)
expect(s).eq(longString)
})
})
The last example shows how a string of arbitrary length can be stored using the module system. The idea is to partition a long string into constant size chunks, deploy each chunk in a separate module, and then deploy one additional module that recombined the modules for the chunks and exports their concatenation. In the example the "recombining" module is as follows:
import { c0 } from 'f86ec90ce2ab7367e197df1e63b45114a381d5636dc85e35dc28d721fbf0c228:0' // stores '000'
import { c1 } from 'ae90c7aa091045239d61011c770754b8cd8409541e56177d2a15e591e337bd67:0' // stores '000'
import { c2 } from '5530cfcc89fde62c2cfab4eea56e3aa2d41071480b7b094d7a01316776712701:0' // stores '000'
import { c3 } from 'dc63fbf200595012b239d69936ac63e4155040042ef7d2e6dff4ca49dec3f51e:0' // stores '0'
export const s = c0 + c1 + c2 + c3