Subcurrency
The following contract implements the simplest form of a cryptocurrency. The contract allows the creation of new coins (i.e. minting) as well as sending coins from one address to another.
storage {
total_supply: int,
balances: (b256 => int),
}
// Sends an amount of newly created coins to an address
predicate Mint(receiver: b256, amount: int) {
constraint storage::total_supply := storage::total_supply! + amount;
constraint storage::balances[receiver] := storage::balances[receiver]! + amount;
}
// Sends an amount of existing coins from address `from` to address `receiver`
predicate Send(from: b256, receiver: b256, amount: int) {
let from_balance = storage::balances[from]!;
let receiver_balance = storage::balances[receiver]!;
constraint amount < from_balance;
constraint storage::balances[from] := from_balance - amount;
constraint storage::balances[receiver] := receiver_balance + amount;
}
This contract introduces some new concepts. Let's walk through it line by line.
The contract starts with a storage declaration that contains two storage variables:
total_supplyis of typeintand represents the total supply of coins available at any given point in time.balancesis a map fromb256tointand stores balances of addresses as integers.b256is a primitive type that represents a 256-bit hash value and is used here to represent an address.
The contract also declares two predicates: Mint and Send.
The Mint predicate is fairly simple:
- It has two parameters
receiver: b256andamount: int. The goal of this predicate to mintamountcoins and send them toreceiver. - It initializes a local variable called
receiver_balanceusing the storage access expressionmut storage::balances[receiver]. This syntax returns the value inbalancesthatreceivermaps to and makes it "mutable". The predicate also initializes another local variable calledtotal_supplytomut storage::total_supply. - It enforces two constraints:
- The first constraint requires the total supply to be incremented by
amount. - The second constraint requires the balance of
receiverto be incremented byamount.
- The first constraint requires the total supply to be incremented by
The Send predicate has the following structure:
- It has three parameters
from: b256,receiver: b256, andamount: int. The goal of this predicate to sendamountcoins from addressfromto addressreceiver. - It initializes a local variable called
from_balanceto the balance offromand another variable calledreceiver_balanceto the balance ofreceiver. It also makes both balances "mutable". - It enforces three constraints
- The first constraint requires
from_balanceto be larger thanamount. That is, the addressfrommust currently actually have enough coins to send toreceiver. - The second constraint effectively decrements the balance of
frombyamount, by requiring the next state offrom_balanceto befrom_balance - amount. - The third constraint effectively increments the balance of
receiverbyamount, by requiring the next state ofreceiver_balanceto bereceiver_balance + amount.
- The first constraint requires
Note to make things simpler and easier to understand, this contract has no authentication anywhere in its code. That is, anyone can mint new coins and initiate a transfer from one arbitrary address to another. This, of course, is not the desired behavior for most cryptocurrencies. That being said, examples of authentication can be found in this Github repository.