Quickstart
Installation
To use the rubi sdk, first install it using pip
or poetry
:
(.venv) $ pip install rubi
(.venv) $ poetry add rubi
Using rubi
This quickstart guide aims highlight the most common use case of rubi, connecting to and trading on the Rubicon Protocol.
This sdk depends on a connection to an Ethereum node by relying on the web3.py library. Please refer to their documentation if you want to understand what is going on behind the scenes.
rubi client
The main entrypoint of this library is the rubi client. In order to instantiate a client we will need to
provide it with some environment variables, namely a HTTP_NODE_URL
, WALLET
and KEY
. While not strictly
necessary it is best practice to provide this from a .env
file.
Note
If you are working in a git repository make sure you add a .gitignore
and ignore .env
files to ensure you never commit sensitive information.
Create a .env
file with the following format:
HTTP_NODE_URL = <an optimism http node url>
WALLET = <the wallet that is being used to sign transactions and pay gas for said transactions>
KEY = <the private key of the wallet being used to sign transactions>
Following this you will need to read in these environment variables. The easiest way to do this is using the python
dotenv
library.
(.venv) $ pip install python-dotenv
(.venv) $ poetry add python-dotenv
This will allow you to read in your environment variables as follows:
import logging as log
import os
from dotenv import load_dotenv
# load from env file
load_dotenv(".env")
# set the env variables
http_node_url = os.getenv("HTTP_NODE_URL")
wallet = os.getenv("WALLET")
key = os.getenv("KEY")
Finally we are ready to instantiate a client
# rubi imports
from rubi import Client, NetworkName, Transaction, NewLimitOrder, OrderSide
# instantiate the client
client = Client.from_http_node_url(
http_node_url=http_node_url,
wallet=wallet,
key=key
)
Note
In the above example we are creating a client using the from_http_node_url
function. This fetches the chain id from the node and then maps this to default network config that is managed by the Rubicon team. This config can be seen here. If you prefer you can instantiate your own Network
instance and use that to instantiate the client.
Note
In the above example we are connecting to the optimism goerli testnet. Make sure the node you are using is an optimism goerli node.
Having instantiated a client you are now ready to start interacting with the Rubicon protocol. In order to use the client to read or trade against a specific pair you will need to first add the pair to the client.
# add the WETH/USDC pair to the client
# the base asset is WETH and the quote asset is USDC
client.add_pair(
pair_name="WETH/USDC",
base_asset_allowance=Decimal("1"),
quote_asset_allowance=Decimal("10000")
)
Note
The allowances in the code above approve the RubiconMarket
contract to transact up to that amount on your wallets behalf. This is necessary in order to create offers on the protocol.
Now with a pair created you can place your first limit order on Rubicon the decentralized world orderbook!
limit_order = NewLimitOrder(
pair_name="WETH/USDC",
order_side=OrderSide.BUY,
size=Decimal("1"),
price=Decimal("1914.13")
)
client.place_limit_order(
transaction=Transaction(
orders=[limit_order]
)
)
That brings us to the end of the quickstart. Next see the Overview of the client’s current functionality.
READ ONLY rubi client
To create a read only rubi client follow the steps above except when creating your .env
file DO NOT
add a WALLET
or KEY
. Instead your .env
file should only contain the following
HTTP_NODE_URL = <an optimism http node url>
The rubi client will then be instantiated without signing rights. You will still have read access to all the Rubicon contracts.
That brings us to the end of the quickstart. Next see the Overview of the client’s current functionality.
rubi client pairs and tokens
The rubi client uses the notion of a pair
to effectively translate from offers on the Rubicon
protocol to the more understandable notions of bids and asks.
Whenever you want to trade a specific set of tokens you will first need to add this pair to the client
# add the WETH/USDC pair to the client
# the base asset is WETH and the quote asset is USDC
client.add_pair(
pair_name="WETH/USDC",
base_asset_allowance=Decimal("1"),
quote_asset_allowance=Decimal("10000")
)
If you add the WETH/USDC
pair as in the above example then you are saying you want to think of trading WETH
in
terms of USDC
. In other words, all orders and the client orderbook will price WETH
in terms of USDC
, so for
example, if you wanted to create a new limit order you would say I want to sell 1 WETH
for 2000 USDC
. It should
be noted that there is no need to price assets in stable coin terms. In fact, being in defi it probably makes more sense
to price things in terms of WETH
;).
client.add_pair(
pair_name="USDC/WETH",
base_asset_allowance=Decimal("1"),
quote_asset_allowance=Decimal("10000")
)
By default when you instantiate a rubi client you will only be able to create pairs from the tokens
found in the token_addresses
section of the network.yaml
config for the chain you are connected to. This set of
token addresses is vetted by the Rubicon team and intended to ensure that in interacting with the protocol users do not
fall victim to scam coins. However, when instantiating the client you can provide an additional
custom_token_addresses_file
parameter
client = Client.from_http_node_url(
http_node_url=http_node_url,
custom_token_addresses_file="custom_token_addresses.yaml",
wallet=wallet,
key=key
)
This points to a yaml file (which is relative to the current working directory) containing token addresses in the following format
# Forrest coin and USDT on Optimism Goerli
F: 0x45fa7d7b6c954d17141586e1bd63d2e35d3e26de
USDT: 0xd70734ba8101ec28b38ab15e30dc9b60e3c6f433
These additional tokens will then be appended to the valid tokens found in the network.yaml
.
Additionally, it should be noted that you can override the addresses found in token_addresses
section of the
network.yaml
by adding the same key to the custom_token_addresses_file
.
Warning
THIS IS SUPER RISKY. I HOPE YOU KNOW WHAT YOU’RE DOING IF YOU CHOOSE TO DO THIS.
USDC: 0xFAKEfakeFAKEfakeFAKEfakeFAKEfakeFAKEfake
This will result in the client being instantiated with the address of
USDC
as 0xFAKEfakeFAKEfakeFAKEfakeFAKEfakeFAKEfake
.
rubi data methods
In this section, we will go through some methods in the Client
and MarketData
classes of the Rubicon package, specifically the get_offers
and get_trades
methods. We’ll also illustrate how to use these methods with a basic example at the end.
The get_offers Method
This method is used to retrieve offers placed on the market contract. Users can filter the offers based on various parameters including the maker’s address, transaction origin address, tokens involved in the transaction, etc.
Here’s the signature of the method:
def get_offers(
self,
first: int = 10000000,
order_by: str = "timestamp",
order_direction: str = "desc",
formatted: bool = True,
book_side: OrderSide = OrderSide.NEUTRAL,
maker: Optional[Union[ChecksumAddress, str]] = None,
from_address: Optional[Union[ChecksumAddress, str]] = None,
pair_name: Optional[str] = None,
pay_gem: Optional[Union[ChecksumAddress, str]] = None,
buy_gem: Optional[Union[ChecksumAddress, str]] = None,
open: Optional[bool] = None,
start_time: Optional[int] = None,
end_time: Optional[int] = None,
) -> pd.DataFrame:
The method accepts the following parameters:
Parameter |
Description |
---|---|
first |
Number of offers to return |
order_by |
Field to order the offers by. Default is “timestamp” |
order_direction |
Direction to order the offers by. Default is “desc” |
formatted |
Whether or not to return the dataframe with formatted fields (requires node connection) |
book_side |
Specifies which side of the order book to consider |
maker |
The address of the maker of the offer |
from_address |
The address that originated the transaction that created the offer |
pair_name |
Token pair in the format “WETH/USDC” following the pattern <ASSET/QUOTE> |
pay_gem |
The address of the token that the maker is offering. Optional, overrides the pair_name if provided |
buy_gem |
The address of the token that the maker is requesting. Optional, overrides the pair_name if provided |
open |
Whether or not the offer is still active |
start_time |
The unix timestamp of the earliest offer to return |
end_time |
The unix timestamp of the latest offer to return |
The get_trades Method
This method is used to retrieve trades that have occurred on the market contract. Similar to get_offers, users can filter the trades based on various parameters including the taker’s address, transaction origin address, tokens involved in the transaction, etc.
Here’s the signature of the method:
def get_trades(
self,
first: int = 10000000,
order_by: str = "timestamp",
order_direction: str = "desc",
formatted: bool = True,
book_side: OrderSide = OrderSide.NEUTRAL,
taker: Optional[Union[ChecksumAddress, str]] = None,
from_address: Optional[Union[ChecksumAddress, str]] = None,
pair_name: Optional[str] = None,
start_time: Optional[int] = None,
end_time: Optional[int] = None,
) -> pd.DataFrame:
The method accepts the following parameters:
Parameter |
Description |
---|---|
first |
Number of trades to return |
order_by |
Field to order the trades by. Default is “timestamp” |
order_direction |
Direction to order the trades by. Default is “desc” |
formatted |
Whether or not to return the dataframe with formatted fields (requires node connection) |
book_side |
Specifies which side of the order book to consider |
taker |
The address of the taker of the trade |
from_address |
The address that originated the transaction that created the trade (helpful when transactions go through the router) |
pair_name |
Token pair in the format “WETH/USDC” following the pattern <ASSET/QUOTE> |
start_time |
The unix timestamp of the earliest trade to return |
end_time |
The unix timestamp of the latest trade to return |
Retrieving Offer Data
In the example below, we will retrieve WETH/USDC offer data for a given time range on the network of the node connection.
weth_usdc_offers = client.get_offers(
pair_name="WETH/USDC",
book_side=OrderSide.NEUTRAL, # options are NEUTRAL, BUY, SELL
formatted=True, # by default is set to True, if set to False, raw data will be returned (with greater detail)
start_time=1688187600,
end_time=1690606800,
)
Retrieving Trade Data
In the example below, we will access WETH/USDC trade data for a given time range on the network of the node connection.
weth_usdc_trades = client.get_trades(
pair_name="WETH/USDC",
book_side=OrderSide.NEUTRAL, # options are NEUTRAL, BUY, SELL
formatted=True, # by default is set to True, if set to False, raw data will be returned (with greater detail)
start_time=1688187600,
end_time=1690606800,
)