Oracle client written in bash that utilizes secure scuttlebutt for offchain message passing along with signed price data to validate identity and authenticity on-chain.
Goals of this new architecture are:
- Scalability,
- Reduce costs by minimizing number of ethereum transactions and operations performed on-chain,
- Increase reliability during periods of network congestion,
- Reduce latency to react to price changes,
- Make it easy to on-board price feeds for new collateral types, and
- Make it easy to on-board new Oracles.
There are currently two main modules:
Each Feed runs a Feed client which pulls prices redundantly with Setzer and Oracle Suite/Gofer, signs them with an ethereum private key, and broadcasts them as a message to the redundant p2p networks (e.g. scuttlebutt and libp2p).
Relays monitor the broadcast messages, check for liveness, and homogenize the pricing data and signatures into a single ethereum transaction to be posted to the on-chain oracles.
The sample generic configurtion file are present in ./systemd/
folder.
Ubuntu 22.04
nix-build (Nix) 2.13.2
To build from inside this repo, clone and run:
nix-build
The setup scripts can also be used configure Omnia as a feed running with systemd
:
The setup scripts can also be used configure Omnia as a relay running with systemd
but first make sure spire is running:
sudo ./setup/run_it_relay.sh --omnia <ABSOLUTE_PATH_OF_CONFIG> --spire <ABSOLUTE_PATH_OF_CONFIG>
for example:
sudo ./setup/run_it_relay.sh --omnia /home/oracles/omnia_relay.json --spire /home/oracles/spire1.json
If you want to run multiple omnia's feed instances then you have to change the name of the systemd files(omnia.service
, spire-agent.service
) which are generated by ./setup/run_feed.sh
or ./setup/run_it_relay.sh
and change the config files path for shell script for example: sudo ./setup/run_it_relay.sh --omnia /home/oracles/omnia2.json --spire /home/oracles/spire.json
and run the shell script again.
you can run the omnia, spire and gofer with systemd by these command:
systemctl start omnia.service
systemctl start gofer-agent.service
systemctl start spire-agent.service
the gofer is configured by its configurations and the sample config is stated below. It uses HCL file for configuration; HCL File should be same for Gofer and Spire
spire is installed through nix.
It uses HCL file for configuration; HCL File should be same for Gofer and Spire
This is based on libp2p which is a peer-to-peer networking protocol designed to enable decentralized communication and file sharing over the internet. It is a modular, open-source networking protocol that allows nodes to communicate with each other directly, without the need for a central server or infrastructure.
One of these attributes is the "transport" attribute, which uses libp2p to establish direct peer-to-peer connections between nodes without relying on a central server or infrastructure, So we have to give the listenAddrs for example /ip4/192.168.18.109/tcp/37705/p2p/12D3KooWPFpaE13gph8p6jdNGJv1M6fwDro8kdst53MUzVpuSJUL
i.e "<ip-version>/<host>/<protocol>/<port>/<type>/<peer_id>" w.r.t the quorum of median.To obtain the peer addresses, you can check the logs of Spire using journalctl, as Spire runs as a systemd service. Once you have the peer addresses, then ** you can add them to the "directPeersAddrs" array to connect peers in the "transport" attribute of the Spire configuration file. **
sudo journalctl -u <spire-agent.service> -n 100 -b -f
add peerIDs in this attr to connect spire with each other
"transport" {
"libp2p" {
"directPeersAddrs"=["Add listen address here"]}}
spire agent -c <CONFIG_PATH> --log.verbosity debug
systemctl start <spire-agent.service>
systemctl start <ssb-server.service>
The installed Scuttlebot config can be found in ~/.ssb.config
, more details
about the Scuttlebot config.
Open the systemd file of ssb-server.service to lookup the binary of ssb-server.
Creating an SSB Invite
ssb-server invite.create 1
means <path of ssb-server> invite.create 1
This will output a JSON object containing the invite code.
Accepting an SSB Invite
To accept an SSB invite without using Docker, open a terminal window and run the following command:
ssb-server invite.accept <invite_code>
Replace <invite_code> with the invite code obtained in the previous step.
we should run the 3 feeds with the 3 spires every feed should have their own omnia means the config file have the right omnia addr pasted in feed object of spire's config
Example configuration:Relay
{
"mode": "relay",
"ethereum": {
"from": "0x",
"keystore": "",
"password": "",
"network": "goerli",
"gasPrice": {
"source": "node",
"multiplier": 1
}
},
"transports":["ssb"],
"feeds": [
"0xdeadbeef123"
],
...
}
Example configuration:Feed
{
"mode": "feed",
"ethereum": {
"from": "0x86B5B8Fe2B467F733c0624e13b9Df08867d94B96",
"keystore": "/home/admin/.ethereum/keystore",
"password": "/home/admin/.ethereum/keystore/.pass",
"type": "ethereum",
"network": "http://127.0.0.1:8545"
},
"options": {
"interval": 60,
"msgLimit": 35,
"srcTimeout": 10,
"setzerTimeout": 10,
"setzerCacheExpiry": 120,
"setzerMinMedian": 1,
"setzerEthRpcUrl": "http://127.0.0.1:9989",
"verbose": true,
"logFormat": "text"
},
"sources": [
"gofer","setzer"
],
"transports": [
"spire"
],
"pairs": {
"ETH/USD": {
"msgExpiration": 1800,
"msgSpread": 0.5
}
}
}
Example configuration: SPIRE && GOFER
variables {
# List of feeds that are allowed to send price updates and event attestations.
feeds = try(env.CFG_FEEDS == "" ? [] : split(",", env.CFG_FEEDS), [
"0x125fC0CcCDee5ac474062F6358d4d056b0430b84",
"0x37c273044A6ef7c9D09670C8246c49FF4CfD2511",
"0x34050B9d0630594214008e3a2af07107B71831fd"
])
}
ethereum {
rand_keys = try(env.CFG_ETH_FROM, "0x125fC0CcCDee5ac474062F6358d4d056b0430b84") == "" ? ["default"] : []
dynamic "key" {
for_each = try(env.CFG_ETH_FROM, "0x125fC0CcCDee5ac474062F6358d4d056b0430b84") == "" ? [] : [1]
labels = ["default"]
content {
address = try(env.CFG_ETH_FROM, "0x125fC0CcCDee5ac474062F6358d4d056b0430b84")
keystore_path = try(env.CFG_ETH_KEYS, "/home/usman/.ethereum/keystore")
passphrase_file = try(env.CFG_ETH_PASS, "/home/usman/.ethereum/keystore/.pass")
}
}
client "default" {
rpc_urls = try(env.CFG_ETH_RPC_URLS == "" ? [] : split(",", env.CFG_ETH_RPC_URLS), [
"https://goerli.infura.io/v3/de82b2d602264e4fbc0929dec0c45baa"
])
chain_id = 1
ethereum_key = "default"
}
client "arbitrum" {
rpc_urls = try(env.CFG_ETH_ARB_RPC_URLS == "" ? [] : split(",", env.CFG_ETH_ARB_RPC_URLS), [
"https://arbitrum.public-rpc.com"
])
chain_id = 42161
ethereum_key = "default"
}
client "optimism" {
rpc_urls = try(env.CFG_ETH_OPT_RPC_URLS == "" ? [] : split(",", env.CFG_ETH_OPT_RPC_URLS), [
"https://mainnet.optimism.io"
])
chain_id = 10
ethereum_key = "default"
}
}
transport {
# LibP2P transport configuration. Always enabled.
libp2p {
feeds = var.feeds
priv_key_seed = try(env.CFG_LIBP2P_PK_SEED, "")
listen_addrs = try(split(",", env.CFG_LIBP2P_LISTEN_ADDRS), ["/ip4/0.0.0.0/tcp/8779"])
direct_peers_addrs = []
blocked_addrs = try(env.CFG_LIBP2P_BLOCKED_ADDRS == "" ? [] : split(",", env.CFG_LIBP2P_BLOCKED_ADDRS), [])
disable_discovery = false
ethereum_key = try(env.CFG_ETH_FROM, "0x125fC0CcCDee5ac474062F6358d4d056b0430b84") == "" ? "" : "default"
}
}
spire {
rpc_listen_addr = try(env.CFG_SPIRE_RPC_ADDR, "0.0.0.0:9105")
rpc_agent_addr = try(env.CFG_SPIRE_RPC_ADDR, "127.0.0.1:9105")
# List of pairs that are collected by the spire node. Other pairs are ignored.
pairs = try(env.CFG_SPIRE_PAIRS == "" ? [] : split(",", env.CFG_SPIRE_PAIRS), [
"BTC/USD",
"USDT/GSU"
])
}