Skip to content

Commit

Permalink
feat: osmosis provider (#607)
Browse files Browse the repository at this point in the history
Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com>
  • Loading branch information
Alex Johnson and davidterpay authored Jul 25, 2024
1 parent 9f85f7f commit b1bb838
Show file tree
Hide file tree
Showing 24 changed files with 1,507 additions and 161 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ USE_RAYDIUM_MARKETS ?= false
USE_UNISWAPV3_BASE_MARKETS ?= false
USE_COINGECKO_MARKETS ?= false
USE_COINMARKETCAP_MARKETS ?= false
USE_OSMOSIS_MARKETS ?= false
SCRIPT_DIR := $(CURDIR)/scripts
DEV_COMPOSE ?= $(CURDIR)/contrib/compose/docker-compose-dev.yml

Expand All @@ -39,6 +40,7 @@ export USE_RAYDIUM_MARKETS ?= $(USE_RAYDIUM_MARKETS)
export USE_UNISWAPV3_BASE_MARKETS ?= $(USE_UNISWAPV3_BASE_MARKETS)
export USE_COINGECKO_MARKETS ?= $(USE_COINGECKO_MARKETS)
export USE_COINMARKETCAP_MARKETS ?= $(USE_COINMARKETCAP_MARKETS)
export USE_OSMOSIS_MARKETS ?= $(USE_OSMOSIS_MARKETS)
export SCRIPT_DIR := $(SCRIPT_DIR)

BUILD_TAGS := -X github.com/skip-mev/slinky/cmd/build.Build=$(TAG)
Expand Down
120 changes: 120 additions & 0 deletions cmd/constants/marketmaps/markets.go
Original file line number Diff line number Diff line change
Expand Up @@ -9600,6 +9600,115 @@ var (
}
}
`

// OsmosisMarketMap is used to initialize the osmosis market map. This only includes
// the markets that are supported by osmosis.
OsmosisMarketMap mmtypes.MarketMap

// OsmosisMarketMapJSON is the JSON representation of OsmosisMarketMap.
OsmosisMarketMapJSON = `
{
"markets": {
"STARS/USD": {
"ticker": {
"currency_pair": {
"Base": "STARS",
"Quote": "USD"
},
"decimals": 18,
"min_provider_count": 1,
"enabled": true,
"metadata_JSON": "{\"reference_price\":1,\"liquidity\":0,\"aggregate_ids\":[]}"
},
"provider_configs": [
{
"name": "osmosis_api",
"off_chain_ticker": "STARS/OSMO",
"metadata_JSON": "{\"pool_id\":1096,\"base_token_denom\":\"ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4\",\"quote_token_denom\":\"uosmo\"}",
"normalize_by_pair": {
"Base": "OSMO",
"Quote": "USD"
}
}
]
},
"USDT/USD": {
"ticker": {
"currency_pair": {
"Base": "USDT",
"Quote": "USD"
},
"decimals": 9,
"min_provider_count": 1,
"enabled": true
},
"provider_configs": [
{
"name": "binance_ws",
"off_chain_ticker": "USDCUSDT",
"invert": true
},
{
"name": "bybit_ws",
"off_chain_ticker": "USDCUSDT",
"invert": true
},
{
"name": "coinbase_ws",
"off_chain_ticker": "USDT-USD"
},
{
"name": "kraken_api",
"off_chain_ticker": "USDTZUSD"
},
{
"name": "okx_ws",
"off_chain_ticker": "USDC-USDT",
"invert": true
},
{
"name": "crypto_dot_com_ws",
"off_chain_ticker": "USDT_USD"
}
]
},
"OSMO/USD": {
"ticker": {
"currency_pair": {
"Base": "OSMO",
"Quote": "USD"
},
"decimals": 8,
"min_provider_count": 1,
"enabled": true,
"metadata_JSON": "{\"reference_price\":1,\"liquidity\":0,\"aggregate_ids\":[]}"
},
"provider_configs": [
{
"name": "coinbase_ws",
"off_chain_ticker": "OSMO-USD"
},
{
"name": "huobi_ws",
"off_chain_ticker": "osmousdt",
"normalize_by_pair": {
"Base": "USDT",
"Quote": "USD"
}
},
{
"name": "binance_api",
"off_chain_ticker": "OSMOUSDT",
"normalize_by_pair": {
"Base": "USDT",
"Quote": "USD"
}
}
]
}
}
}
`
)

func init() {
Expand Down Expand Up @@ -9652,4 +9761,15 @@ func init() {
fmt.Fprintf(os.Stderr, "failed to validate CoinGeckoMarketMap: %v\n", err)
panic(err)
}

// Unmarshal the OsmosisMarketMapJSON into OsmosisMarketMap.
if err := json.Unmarshal([]byte(OsmosisMarketMapJSON), &OsmosisMarketMap); err != nil {
fmt.Fprintf(os.Stderr, "failed to unmarshal OsmosisMarketMapJSON: %v\n", err)
panic(err)
}

if err := OsmosisMarketMap.ValidateBasic(); err != nil {
fmt.Fprintf(os.Stderr, "failed to validate OsmosisMarketMap: %v\n", err)
panic(err)
}
}
5 changes: 5 additions & 0 deletions cmd/constants/marketmaps/markets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ func TestMarkets(t *testing.T) {
var mm5 mmtypes.MarketMap
require.NoError(t, json.Unmarshal([]byte(marketmaps.CoinMarketCapMarketMapJSON), &mm5))
require.NoError(t, marketmaps.CoinMarketCapMarketMap.ValidateBasic())

// Unmarshal the OsmosisMarketMapJSON into OsmosisMarketMap.
var mm6 mmtypes.MarketMap
require.NoError(t, json.Unmarshal([]byte(marketmaps.OsmosisMarketMapJSON), &mm6))
require.NoError(t, marketmaps.OsmosisMarketMap.ValidateBasic())
}
6 changes: 6 additions & 0 deletions cmd/constants/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package constants

import (
"github.com/skip-mev/slinky/oracle/config"
"github.com/skip-mev/slinky/providers/apis/defi/osmosis"

"github.com/skip-mev/slinky/oracle/constants"
"github.com/skip-mev/slinky/oracle/types"
Expand Down Expand Up @@ -49,6 +50,11 @@ var (
API: uniswapv3.DefaultBaseAPIConfig,
Type: types.ConfigType,
},
{
Name: osmosis.Name,
API: osmosis.DefaultAPIConfig,
Type: types.ConfigType,
},

// Exchange API providers
{
Expand Down
2 changes: 1 addition & 1 deletion cmd/slinky/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func setViperDefaultsForDataStructure(keyPrefix string, config interface{}) {
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
}

// ReadOracleConfigFromFile reads a config from a file and returns the config.
// ReadOracleConfigWithOverrides reads a config from a file and returns the config.
func ReadOracleConfigWithOverrides(path string, marketMapProvider string) (config.OracleConfig, error) {
// if the path is non-nil read data from a file\
SetDefaults()
Expand Down
5 changes: 3 additions & 2 deletions contrib/compose/docker-compose-dev.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.7'

networks:
oracle_network:
driver: bridge
Expand All @@ -16,6 +14,7 @@ services:
"--use-uniswapv3-base=$USE_UNISWAPV3_BASE_MARKETS",
"--use-coingecko=$USE_COINGECKO_MARKETS",
"--use-coinmarketcap=$USE_COINMARKETCAP_MARKETS",
"--use-osmosis=$USE_OSMOSIS_MARKETS",
"--temp-file=data/markets.json",
]
environment:
Expand All @@ -24,6 +23,7 @@ services:
- USE_UNISWAPV3_BASE_MARKETS=${USE_UNISWAPV3_BASE_MARKETS:-false}
- USE_COINGECKO_MARKETS=${USE_COINGECKO_MARKETS:-false}
- USE_COINMARKETCAP_MARKETS=${USE_COINMARKETCAP_MARKETS:-false}
- USE_OSMOSIS_MARKETS=${USE_OSMOSIS_MARKETS:-false}
volumes:
- markets_data:/data
networks:
Expand Down Expand Up @@ -63,6 +63,7 @@ services:
- USE_UNISWAPV3_BASE_MARKETS=${USE_UNISWAPV3_BASE_MARKETS:-false}
- USE_COINGECKO_MARKETS=${USE_COINGECKO_MARKETS:-false}
- USE_COINMARKETCAP_MARKETS=${USE_COINMARKETCAP_MARKETS:-false}
- USE_OSMOSIS_MARKETS=${USE_OSMOSIS_MARKETS:-false}
build:
context: ../..
dockerfile: ./contrib/images/slinky.local.Dockerfile
Expand Down
3 changes: 2 additions & 1 deletion pkg/grpc/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (
"net"
"testing"

slinkygrpc "github.com/skip-mev/slinky/pkg/grpc"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"

slinkygrpc "github.com/skip-mev/slinky/pkg/grpc"
)

func TestClient(t *testing.T) {
Expand Down
52 changes: 52 additions & 0 deletions pkg/http/round_tripper_with_headers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package http

import (
"context"
"errors"
"fmt"
"net/http"

Expand Down Expand Up @@ -58,3 +60,53 @@ func (r *RoundTripperWithHeaders) RoundTrip(req *http.Request) (*http.Response,

return r.next.RoundTrip(req)
}

// Client is a wrapper around the Go stdlib http client.
type Client struct {
internal *http.Client
}

// NewClient returns a new Client with its internal http client
// set to the default client.
func NewClient() *Client {
return &Client{
internal: http.DefaultClient,
}
}

type GetOptions func(*http.Request)

func WithHeader(key, value string) GetOptions {
return func(r *http.Request) {
r.Header.Add(key, value)
}
}

func WithJSONAccept() GetOptions {
return func(r *http.Request) {
r.Header.Add("Accept", "application/json")
}
}

// GetWithContext performs a Get request with the context provided.
func (c *Client) GetWithContext(ctx context.Context, url string, opts ...GetOptions) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}

for _, opt := range opts {
opt(req)
}

resp, err := c.internal.Do(req)
if err != nil {
return nil, fmt.Errorf("http get: %w", err)
}

if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}

return resp, nil
}
Loading

0 comments on commit b1bb838

Please sign in to comment.