Rubidity by Example
Let's start with some examples from Solidity's introduction.
Storage Example
This basic Solidity contract sets the value of a variable and then exposes it to others to access:
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}Here is how this logic translates to Rubidity:
class Contracts::SimpleStorage < Contract
uint256 :storedData
function :set, { x: :uint256 }, :public do
s.storedData = x
end
function :get, {}, :public, :view, returns: :uint256 do
return s.storedData
end
constructor() {}
endLooking point by point, here's what the Solidity version does and how Rubidity translates it.
Contract Definition
Solidity:
contract SimpleStorage { ... }Rubidity:
class Contracts::SimpleStorage < ContractIn Solidity, you define a contract using the
contractkeyword. In Rubidity, you define a contract as a Ruby class that inherits from a base class calledContract.
State Variable
Solidity:
uint storedData;Rubidity:
uint256 :storedDataSolidity uses the
uintkeyword to define a state variable. Rubidity uses a Ruby symbol to define a state variable along with its type, in this case,uint256.
Function Definitions
Set Function
Solidity:
function set(uint x) public {
storedData = x;
}Rubidity:
function :set, { x: :uint256 }, :public do
s.storedData = x
endThe set function is public in both languages and takes an unsigned integer as an argument. In Rubidity, the function signature also specifies its visibility (:public) and arguments ({ x: :uint256 }).
Get Function
Solidity:
function get() public view returns (uint) {
return storedData;
}Rubidity:
function :get, {}, :public, :view, returns: :uint256 do
return s.storedData
endThe get function is public and has a view property in both languages. The Solidity version uses the returns keyword to specify the return type, while Rubidity does it via the returns: :uint256 option.
Constructor
Solidity: No explicit constructor.
Rubidity:
constructor() {}Both Solidity and Rubidity examples don't utilize a constructor for any initial setup, but the Rubidity code explicitly includes an empty constructor for clarity.
Accessing State
In Rubidity, state variables are accessed using the s. prefix, as seen in s.storedData = x and return s.storedData. Writing to state using an unprefixed variable is not possible in Ruby and the explicitness of s. is nice anyway.
Token Minting Example
Let's break down this OpenMintToken Rubidity contract line-by-line, focusing on how it might translate to a Solidity contract. The contract is an ERC20 token with a capped supply and additional limitations on individual mints.
class Contracts::OpenMintToken < Contract
is :ERC20
uint256 :public, :maxSupply
uint256 :public, :perMintLimit
constructor(
name: :string,
symbol: :string,
maxSupply: :uint256,
perMintLimit: :uint256,
decimals: :uint256
) {
ERC20(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: :addressOrDumbContract, 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
endInheritance:
is :ERC20This line means that the
OpenMintTokencontract inherits from an existing ERC20 contract, inheriting its state variables, functions, and logic.
State Variables:
uint256 :public, :maxSupplyanduint256 :public, :perMintLimitThese lines define two public state variables,
maxSupplyandperMintLimit. Public state variables are accessible to external contracts and can also have getter methods generated automatically.
Constructor:
ruby constructor( name: :string, symbol: :string, maxSupply: :uint256, perMintLimit: :uint256, decimals: :uint256 )The constructor function initializes the contract. It takes the token's name, symbol, maximum supply, per-mint limit, and decimals as parameters.
State Variable Initialization:
s.maxSupply = maxSupplyands.perMintLimit = perMintLimitThese lines initialize the state variables using the
s.prefix, which is specific to Rubidity for accessing and manipulating state variables.
Mint Function:
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) endThis is a public function to mint new tokens. The
requirestatements serve as checks that theamountis positive, within the per-mint limit, and won't exceed the max supply._mintis a likely internal function inherited from the ERC20 contract that actually mints the tokens.
Airdrop Function:
function :airdrop, { to: :addressOrDumbContract, 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) endSimilar to the
mintfunction but allows specifying a recipient addressto. It performs the samerequirechecks and then invokes_mintto create the tokens for the target address.
The Rubidity code uses specific language constructs that mirror Solidity but in a Ruby-like syntax, making it more expressive while maintaining similar logic and functionalities.
Last updated