Kaspalytics Learn is under (heavy) construction. Check back regularly!
Updated: Aug 14, 2026

SilverScript

Kaspa's high-level covenant language - what it is, compiling a contract to a locking script, building unlocking scripts, and stateful covenants.

SilverScript is a CashScript-inspired language for writing native Kaspa script contracts, so covenants do not have to be written in raw opcodes. You write a contract, compile it to a locking script, and lock funds behind that script’s hash - a P2SH address. To spend them, you call one of the contract’s entrypoints and the tooling turns that call into the unlocking script the node accepts.

In the author’s words:


“SilverScript is Kaspa’s first high-level smart contract language and compiler. It enables DeFi, vaults, and native asset management directly on Kaspa’s L1.

The language syntax is based on CashScript, but adds essential features like loops, arrays, and function calls.

It specializes in managing contracts with local state (UTXO model), serving as a complement and infrastructure layer for vProgs (shared state).

~ Ori Newman (link)


Experimental. SilverScript, its compiler output, and the SDK bindings are all under active development and subject to breaking changes. Pin your versions, and don’t lock real value behind a contract you haven’t verified end to end on testnet first.

What the tooling gives you

  • Compile SilverScript source into a locking script.
  • Build the unlocking script for an entrypoint call, mapping your arguments to the contract’s ABI.
  • Debug a call locally - simulate the spend and get a source-level failure report with decoded variables, before you spend anything on chain.

Everything after that is an ordinary Kaspa transaction flow: wrap the locking script in a P2SH address, build and sign the transaction, submit it. See Transactions.

Language support

SilverScript lives in its own Rust workspace, so the surfaces differ by language:

LanguageHow you get it
RustThe silverscript-lang crate - compile_contract and the AST types directly.
Pythonkaspa.experimental.silverscript, a sub-package of the Kaspa SDK.
CLIsilverc, which compiles .sil files to a JSON artifact (bytecode + ABI).
JavaScriptNo binding today. Compile with silverc and load the artifact’s script bytes.

The compiler’s whole interface to the rest of the SDK is script bytes. Compile, read the script, then build the transaction with the core SDK as usual - the compiler never sees an Address or a ScriptBuilder.

When to use it

  • Stateful covenants - contracts that carry state from one UTXO to the next: a counter, an escrow, a vault. See Covenants.
  • Custom locking conditions that are awkward to hand-assemble from raw opcodes, where a typed, readable language helps.

If you only need standard pay-to-public-key or multisig, you do not need SilverScript.

A contract

A minimal Guard that only lets a spend through when amount exceeds a threshold baked in at compile time:

pragma silverscript ^0.1.0;

contract Guard(int threshold) {
    entry check(int amount) {
        require(amount > threshold);
    }
}

entry marks a branch as externally invocable; plain function declares an internal helper an entry can call.

Syntax change. entry name(...) replaced the older entrypoint function name(...) spelling in SilverScript #187. Contracts written against the old keyword no longer parse on master. The Kaspa Python SDK pins a SilverScript revision from before that change, so entrypoint function may still compile through kaspa.experimental.silverscript until the SDK bumps its pin - write entry either way.

Compile and lock

Compile with the constructor argument threshold = 100, wrap the resulting redeem script in a P2SH lock, and turn that into a fundable address:

use silverscript_lang::ast::Expr;
use silverscript_lang::compiler::{compile_contract, CompileOptions};

let source = r#"
    pragma silverscript ^0.1.0;
    contract Guard(int threshold) {
        entry check(int amount) {
            require(amount > threshold);
        }
    }
"#;

let compiled = compile_contract(source, &[Expr::Int(100)], CompileOptions::default())?;

println!("contract: {}", compiled.contract_name);
println!("compiler: {}", compiled.compiler_version);
println!("script: {} bytes", compiled.script.len());
println!("abi: {:?}", compiled.abi);
import kaspa.experimental.silverscript as silverscript
from kaspa import ScriptBuilder, address_from_script_public_key

SOURCE = """
pragma silverscript ^0.1.0;
contract Guard(int threshold) {
    entry check(int amount) {
        require(amount > threshold);
    }
}
"""

# Compile with the constructor arg threshold = 100.
contract = silverscript.compile(SOURCE, [100])

# The redeem script.
redeem = contract.script

# Wrap it in a P2SH lock and turn that into a fundable address.
spk = ScriptBuilder.from_script(redeem).create_pay_to_script_hash_script()
addr = address_from_script_public_key(spk, "testnet")
# Compile to a JSON artifact containing contract_name, compiler_version,
# script (bytecode), ast, and abi.
silverc guard.sil -o guard.json

# With constructor arguments, supplied as a JSON array of typed expressions:
#   [{"kind": "int", "data": 100}]
silverc guard.sil --constructor-args args.json

Funds sent to that address are locked behind the contract.

Spending

To spend, build the unlocking script for the entrypoint call - check(amount) - and use it as the input’s signature script. The Python bindings take plain Python values (int, bool, str, bytes, lists, dicts) and map them onto the contract’s declared parameter types; passing the wrong type is an error at build time rather than a script failure on chain.

Stateful covenants use a separate call that additionally binds the covenant declaration, so the compiler can enforce the state transition the contract declares.

Debugging

debug_call simulates a spend locally and, on failure, reports which require failed, at which source line, with the decoded values of the variables in scope. There is also a standalone source-level stepping debugger in the SilverScript workspace:

cargo run -p cli-debugger -- contract.sil \
  --function check \
  --ctor-arg 100 \
  --arg 150

Use it before every on-chain spend; a failed unlock on chain costs a transaction and provides little diagnostic information.

Resources

Runnable examples

Language and conventions

  • SilverScript tutorial - the full language reference: types, control flow, transaction introspection, covenant builtins.
  • Covenant declaration spec - the #[covenant(...)] attribute that generates leader/delegator transitions for you.
  • KCC20 book - the fungible-token convention built on top of it.

Tooling and walkthroughs

Kaspalytics strives to provide accurate data - our highest level of effort is given to data validation and maintenance. However, we cannot guarantee 100% accuracy. Data is subject to inaccuracies and change.

Contact | © 2026 Kaspalytics