Contractum is a functional declarative programming language designed for developing smart contracts which run on Bitcoin and Lightning network using RGB technology.
Contractum differs from other smart contract programming languages in a fact that as functional as Haskell and nearly as close to the bare metal as Rust at the same time, filling in the space which was not accessible for the smart contracts before:
RGB smart contracts
Contractum is the language to write RGB contracts. RGB is a technology which allows creation of arbitrary-complex ("Turing-complete") smart contracts that run on bitcoin and, most imporangly, Lightning network. RGB contracts are confidential, scalable (up to the speed of the Lightning transactions, with small data footprint) and robust.
Contracts written with Contractum are verified with client-side-validation, which does not adds data to a bitcoin blockchain and may be thought as a sharding technology, enhanced with zero-knowledge. Client-side-validation also breaks transaction graphs, unlinking contract evolution from blockchain transactions, making chain analysis impossible.
Work in progress
The contractum is a work in progress: the language design is under active development at the LNP/BP Association. Everyone is welcome to join the effort; a good starting point can be reading and writing to the language design discussions group in GitHub.
To understand and participate in contractum design it is important to learn more about technologies which are used by RGB smart contracts:
The feel of the language
If you'd like to get a feel of the language, here is a sample contract written in Contractum:
types DiddataPgpKey:: curve U8, key Bytesschema DecentralizedIdentity-- This defines the atom of the contract state called `Identity` which has data -- type `PgpKey`.-- The `owned` keyword means that there is always a party which owns the identity owned Identity :: Did.PgpKey owned IOYIssue ::Zk64-- `Zk64` means 64-bit unsigned integer hidden with zero-knowledge owned IOYTokens ::Zk64 global IOYTicker ::String global IOYName ::String-- This says that to construct contract the user must provide information about -- exactly one identity and its IOY tokengenesis::Identity, IOYTicker, IOYName-- Now let's define what a owner of identity can do by executing his/her rights -- via state transitions ("operation" on the state) of predefined forms, like op Revocation :: old Identity-> new Identity-- which does what it says: it revokes existing identity and creates a new one.-- This issues new IOY promises in tokenized form op Promise :: used IOYIssue-> given [IOYTokens]?, remaining IOYIssue? assert used == sum given + (remaining ??0)-- This transfers IOY tokens from one owner to another owner op Transfer :: spent {IOYTokens} -> received [IOYTokens] assert sum spent == sum receivedinterface FungibleToken: global Ticker -> String -- this is similar to schema definition; in fact-- it is a requirement that the schema must provide-- a global state of the String type and link it to-- the "Ticker" name global Name -> String owned Inflation ::Zk64-- pretty much the same applies to assigned state owned Asset ::Zk64 op Issue ::Inflation-> [Asset]?, Inflation?-- and operations op Transfer :: {Asset} -> [Asset]interface PgpIdentity owned Identity ::PgpKey exec Revocation :: old Identity-> new Identity-- Specific schema state may use different naming, for instance because a schema-- can define multiple assets with different names; in that case we will have-- multiple interface implementations referencing different state.implement FungibleToken for DecentralizedIdentity global Ticker := IOYTicker -- this creates a _binding_ of the state defined-- in the schema (*IOYTicker* in this case) to the-- interface global Name := IOYName owned Inflation := IOYIssue owned Asset := IOYTokens op Issue := Promise op Transfer -- here we skip `:=` part since the interface operation name-- matches the name used in the schema. In such cases we can also-- skip the declaration at wholeimplement PgpIdentity for DecentralizedIdentity-- we do not need to put anything here since schema state and operation names-- matches interface requirements and the compiler is able to guess the bindingscontract meSatoshiNakamoto implements DecentralizedIdentity set IOYTicker :="SATN" set IOYName :="Satoshi Promises"-- this defines a genesis state and assigns it to a single-use-seal assign orig Identity := (0xfac503c4641c3deda72a2d00bc9d6ff1094b15276c386efea403746a91436772,1) -> PgpKey(0,0x028730eeeec41802621d177507b086f390ae600ba3ca5e428b13913af4c2cd25b3)transition iLostMyKey executes Revocationvia meSatoshiNakamoto.orig -- specifies the single-use-seal we close to match-- requirements on the valid operation execution-- conditions assign upd Identity := (~,2) -- here we use txid of the bitcoin transaction-- which will be created to hold the commitment to-- this state transition, called "seal witness".-- Since we can not know the txid upfront we use -- `~` sign to indicate the witness transaction id-> PgpKey(0,0x0219db0a4e0eb8cb833608c08d76b9b279ec44a851ab82cc6fd68a9b32624bfa8b)-- the above defines new state and assigns it to a single-use-seal