Quorlin

Kortana's native contract language: looks like Java, reads like English, publishes an Ethereum ABI.

The shape of a contract

One contract per file, in a `.ql` source file. A contract holds fields, events, an optional constructor and functions. Every function begins with `reads` or `writes`, so you can tell which functions can move money by reading down the left edge of the file.

contract Counter {

    number count;
    address owner;

    event Incremented(address indexed by, number newValue);

    constructor {
        owner = caller;
        count = 0;
    }

    reads number value() {
        return count;
    }

    writes number increment() {
        count = count + 1;
        emit Incremented(caller, count);
        return count;
    }
}

Types

Four scalars, and nothing converts between them by itself.

QuorlinHoldsABI type
numberA whole number, 0 to 2²⁵⁶−1uint256
truthyes or nobool
addressAn accountaddress
textUp to 128 bytesstring
list<T>Up to 64 scalars, never storageT[]
bytesUp to 256 opaque bytesbytes
bytes4A four-byte tagbytes4

reads and writes

`reads` may look at state and may not change it. That is proved when the contract is compiled, and it compiles to a static call which the VM refuses to let write. A `reads` function calling a `writes` one is a compile error — `reads` is a promise about what calling a function does, not about its own statements.

`writes` may change state, emit events and call other `writes` functions.

What surprises people coming from Solidity

There is no `msg.sender` — use `caller`. There is no hexadecimal literal and no address literal at all: an address comes from a parameter, a field, `caller`, or `nobody`. Booleans are `yes` and `no`. Logic is `and`, `or`, `not` rather than `&&`, `||`, `!`.

There is no `else if` — nest instead. Braces are mandatory on both arms of an `if`, so the dangling-else ambiguity does not exist. `require` is a keyword, not a function, so it takes no wrapping parentheses and cannot be shadowed.

Arithmetic is checked by default: `+ - * / %` stop the call on overflow, underflow or divide by zero. Wrapping is available as `+% -% *%` and has to be written deliberately.

The constructor takes no arguments. To configure at deploy time, use a one-shot initialiser guarded by a flag.

Execution context

These are values, not calls — write `caller`, not `caller()`.

Built-inTypeMeaning
calleraddressWho called this function — may be another contract
senderaddressThe account that signed the transaction
sentAmountnumberDNR sent with this call
thisContractaddressThis contract's own address
blockNumbernumberCurrent block height
blockTimenumberCurrent block's timestamp
clocknumberThe dPoH sequence — no EVM equivalent
nobodyaddressThe zero address
hashPair(a, b)numberkeccak256(a ‖ b) over two 256-bit words
hasCode(a)truthWhether address a has contract code

Access control uses caller, not sender

`caller` is whoever made this call, which may be another contract. `sender` is the account that signed the transaction. A check against `sender` can be passed by tricking a user into calling through a contract you control, so access control should almost always use `caller`.

writes setCap(number newCap) {
    require caller == owner, "only the owner";
    cap = newCap;
}

How Studio compiles Quorlin

Quorlin is compiled by `quorlinc`, the native compiler in the Kortana node repository. Studio invokes that binary directly through its own compiler API, so the diagnostics, the ABI and the KVM bytecode you see are what the compiler produced — not a reimplementation.

Studio finds the binary by looking at `QUORLIN_COMPILER_PATH`, then at `KORTANA_BLOCKCHAIN_PATH` and the conventional build outputs of the node repository. If none of those resolve, Quorlin building reports itself unavailable with the reason, and editing, the outline, hover documentation, go-to-definition, completion and structural diagnostics all keep working.

Each compile runs in its own temporary directory with a time limit and a trimmed environment, and the directory is removed afterwards.

Deploying a Quorlin contract

A Quorlin deployment is an ordinary contract-creation transaction carrying the KVM bytecode, so it goes through `eth_sendRawTransaction` exactly as Solidity does. There is no separate KVM transaction surface, and no `kvm_*` RPC family is required.

The constructor takes no arguments, so deployment carries the bytecode alone. Configure at deploy time with a one-shot initialiser guarded by a flag.