Contractum: smart-contract language
Contractum is a functional declarative programming language designed for developing smart contracts which run on Bitcoin and Lightning network using RGB technology.
types Did
data PgpKey :: curve U8, key Bytes
schema 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 token
genesis :: 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 received
interface 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 whole
implement 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 bindings
contract 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 Revocation
via 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