Skip to main content
Arkade Language is a contract language for Bitcoin: a set of spend functions over constructor state. The compiler arkadec turns that source into a JSON artifact with two kinds of script. Arkade Script covenants run in the Emulator, and tapscript leaves run in Bitcoin, for example the unilateral exit. The playground runs the compiler in the browser. You do not install anything.

A first contract

Calculator is an example, not a real vault. It has no output constraint and no exit leaf. Compile it to read the output. Do not fund its address.
Calculator.ark
The contract declares the constructor state a and b, which you fix when you instantiate the contract. Each function is one way to spend the output, and result is a witness argument from the spender. The spend succeeds only if each require passes. A function without a modifier is a covenant: it compiles to Arkade Script, and the Emulator runs that script before it signs.
The artifact holds the Arkade Script of each covenant. <a> and <b> are placeholders. Instantiation replaces them with the constructor arguments:
Calculator.asm
Bitcoin Script disables OP_MUL and OP_DIV. In Arkade Script, numbers are BigNums of up to 520 bytes, while Bitcoin Script operands have at most 4 bytes. OP_DIV fails the spend if b is 0. int also has %, <<, and >>. Covenants also have abs, min, max, within, and modExp.

Reading the transaction

A covenant can read the transaction that spends it, which Bitcoin Script cannot do. A bytes32 payout is the 32-byte witness program of the destination, not the full scriptPubKey. Payout sends the whole output to one script and nothing else:
Payout.ark
Each field compiles to an introspection opcode. Each require is one line:
Payout.asm
The output script of output 0 becomes OP_INSPECTOUTPUTSCRIPTPUBKEY followed by OP_DROP. That opcode pushes the witness program and the segwit version, and OP_DROP removes the version. A covenant can also read the transaction (tx.version, tx.locktime, tx.weight, tx.id), any input (tx.inputs), Arkade assets (assets.lookup, tx.assetGroups), and packets (tx.packet). A tapscript function cannot read the transaction. tx.locktime is the nLockTime of the transaction, not a clock, so for time, use checkTime, which compares a timestamp with the Unix time of the Emulator.

Spend paths

The address of a contract is a Taproot output. Each function becomes a leaf of its script tree. The form of the function chooses the leaf: The synthesized leaf of a covenant f needs the signature of the operator and the signature of the tweaked Emulator key:
A covenant and the tapscript functions with its name form one spend group. A spend group is one entry of functions in the artifact. <EMULATOR_KEY:f> is the Emulator key tweaked with the script of the covenant (Key tweak).

The tapscript modifier

tapscript marks a function as Bitcoin Script. Bitcoin checks it, and the Emulator does not take part. Use it for the unilateral exit: a CSV delay, then the signature of the owner. A tapscript body has require statements in a fixed order. The order is an optional hash condition, an optional timelock (older for CSV, after for CLTV), and then exactly one checkSig or checkMultisig. arkd accepts only N-of-N leaves. OwnedPayout adds a signature of the owner and an exit leaf to Payout. The exit leaf waits for serverExitDelay, the exit delay of the operator (CSV delays).
OwnedPayout.ark
pay appears twice. The covenant limits the output, and the tapscript with the same name replaces the synthesized leaf, so pay now needs the signature of the owner and the signatures of the operator and the Emulator. unilateral has no covenant with the same name, so it is a standalone leaf and the Emulator does not take part.

Reserved names

The virtual output model needs three names for Arkade infrastructure, and the compiler reserves them. A constructor parameter or a tapscript input with one of these names fails with collides with a reserved arkd name. The compiler accepts a contract with no exit leaf, and it does not warn.

Artifact

The compiler makes the artifact, a JSON file. It has what a client needs to find the addresses of a contract and to build its spends. The client does not need the compiler or the source. The artifact does two jobs. Like a Solidity ABI, it lists the constructor inputs and the arguments of each function. Like an output descriptor, it holds script templates. A wallet fills the templates with the constructor arguments. This gives the address and the Taproot tree. A wallet depends on the artifact, not on arkadec. The SDK function programFromArtifact loads it (Create a Vault). savings_vault.json is the artifact of the savings vault. The block omits source and updatedAt:
savings_vault.json
constructorInputs lists the constructor parameters in declaration order. Each entry in functions is one spend group. arkade is the Arkade Script of a covenant, as a template. Each leaf has an asm template and a witness list. The list has the values that the spender supplies. <SERVER_EXIT_DELAY> in the exit leaf is not a constructor input. The client binds it (Reserved names). A witness item with injected set to true is a signature that infrastructure supplies: the operator or the Emulator. The wallet does not supply it. fingerprint is the SHA-256 of the artifact without fingerprint and updatedAt. It identifies the content, but it does not prove where the artifact came from, and updatedAt changes at each compile. Keep the artifact that you used for your addresses. Clients build the Taproot tree in the order of the artifact. A different leaf order can change the output key and the address. Recompile a source bundle only with the same compiler version. The compiler README describes each field.

Install and run

You need Rust 1.85 or newer.
Always pass -o. Without it, arkadec writes <stem>.json in the current directory. arkadec prints warnings to stderr and exits with status 0. It exits with a non-zero status on a type or validation error. --no-optimize skips constant folding, static branch removal, and assembly optimization. arkade-bindgen makes typed TypeScript or Go stubs from an artifact.

Placeholders

Write an asset id in a constructor argument in reverse byte order: it is the reverse of the display order. The language also has arrays, structs, loops, Arkade assets, and new for recursive contract instantiation. The compiler README is the reference. The examples/ folder has complete contracts.