Writing a Dumb Contract

Like Smart Contracts, Dumb Contracts are the "apps" that run on the Facet Protocol. Each Dumb Contract has its own self-contained logic and internal state. When the Facet VM executes a transaction, it finds the appropriate Dumb Contract, loads the contracts current state, executes the transaction, and saves the new state (if the state changed).

Here is an example Dumb Contract that implements an ERC20 token that allows anyone to mint for free:

pragma :rubidity, "1.0.0"

import './ERC20.rubidity'

contract :PublicMintERC20, is: :ERC20 do
  uint256 :public, :maxSupply
  uint256 :public, :perMintLimit
  
  constructor(
    name: :string,
    symbol: :string,
    maxSupply: :uint256,
    perMintLimit: :uint256,
    decimals: :uint8
  ) {
    ERC20.constructor(name: name, symbol: symbol, decimals: decimals)
    s.maxSupply = maxSupply
    s.perMintLimit = perMintLimit
  }
  
  function :mint, { amount: :uint256 }, :public do
    require(amount > 0, 'Amount must be positive')
    require(amount <= s.perMintLimit, 'Exceeded mint limit')
    
    require(s.totalSupply + amount <= s.maxSupply, 'Exceeded max supply')
    
    _mint(to: msg.sender, amount: amount)
  end
  
  function :airdrop, { to: :address, amount: :uint256 }, :public do
    require(amount > 0, 'Amount must be positive')
    require(amount <= s.perMintLimit, 'Exceeded mint limit')
    
    require(s.totalSupply + amount <= s.maxSupply, 'Exceeded max supply')
    
    _mint(to: to, amount: amount)
  end
end

Dumb Contracts are written in a new language called Rubidity, which is a cross between Ruby and Solidity. Rubidity uses Ruby syntax but Rubidity isn't always semantically valid Ruby. Instead, before Rubidity can be executed, it is transpiled into Ruby. It is through this process that the line import './ERC20.rubidity' is replaced with actual library code.

In our example from before, the Dumb Contract will receive the user's mint amount as an argument in the mint function. It will perform some validations and then it will call the ERC20 internal _mint function which looks like this:

function :_mint, { to: :address, amount: :uint256 }, :internal, :virtual do
  s.totalSupply += amount
  s.balanceOf[to] += amount
  
  emit :Transfer, from: address(0), to: to, amount: amount
end

Notice there is no explicit state management or "saving" in Rubidity. Just like in Solidity, when you make changes to state variables in Rubidity the VM takes care of ensuring they're persisted. (In Rubidity all state variables are prefixed with s.)

Last updated