Skip to content

Commit

Permalink
feat: redstone price update
Browse files Browse the repository at this point in the history
  • Loading branch information
harsh-98 committed Nov 25, 2024
1 parent ff6a26b commit b610477
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 31 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/Gearbox-protocol/third-eye
go 1.20

require (
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125124726-93c3aff17c9a
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125152813-07a6d49e54db
github.com/ethereum/go-ethereum v1.13.14
github.com/go-playground/validator/v10 v10.4.1
github.com/google/go-cmp v0.5.9
Expand Down Expand Up @@ -82,6 +82,6 @@ require (

replace github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1

replace github.com/Gearbox-protocol/sdk-go v0.0.0-20241119043104-ba1f86094225 => ../sdk-go
replace github.com/Gearbox-protocol/sdk-go v0.0.0-20241125124726-93c3aff17c9a => ../sdk-go

replace github.com/ethereum/go-ethereum v1.13.14 => github.com/OffchainLabs/go-ethereum v1.13.4-0.20240313010929-e5d8587e7227
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeS
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125124726-93c3aff17c9a h1:vmqWyb6ZakENsmkNdRujuIRtk2TxpRQSJ4+PW8FCTTM=
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125124726-93c3aff17c9a/go.mod h1:jRBSOG94bpGc5ci8EWIPUVXZdaGEaekMNmhajbmWFVU=
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125152813-07a6d49e54db h1:IRa3wuCljH3OtCxYbZ9IRwiVHxwsPVgwnVLM+9KbKAg=
github.com/Gearbox-protocol/sdk-go v0.0.0-20241125152813-07a6d49e54db/go.mod h1:jRBSOG94bpGc5ci8EWIPUVXZdaGEaekMNmhajbmWFVU=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/OffchainLabs/go-ethereum v1.13.4-0.20240313010929-e5d8587e7227 h1:+/3TrD+q+BP36jGj2Bycdmrc/joKLNbc5ImePQzKRLM=
Expand Down
13 changes: 13 additions & 0 deletions models/aggregated_block_feed/base_price_feed/token_ds.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type DetailsDS struct {
// redunantt
Reduntant map[string][]int64 `json:"token,omitempty"` // token enabled and disabled at block numbers
MergedPFVersion *schemas.MergedPFVersion `json:"mergedPFVersion,omitempty"`
// for single asset
Underlyings []string `json:"underlyings"`
Info map[string]*core.RedStonePF `json:"info"`
}

// func NewDetailsDS(pfType string, token string, discoveredAt int64, pfVersion schemas.PFVersion) *DetailsDS {
Expand Down Expand Up @@ -52,6 +55,16 @@ func (obj *DetailsDS) Load(in core.Json, version core.VersionType) {
}
}
}
//
a := in["info"]
redstoneMap := map[string]*core.RedStonePF{}
if a != nil {
str := utils.ToJson(a)
err := utils.ReadJsonReaderAndSetInterface(bytes.NewBufferString(str), redstoneMap)
log.CheckFatal(err)
}
obj.Info = redstoneMap
//
obj.Reduntant = nil
obj.MergedPFVersion = nil
// log.Info(utils.ToJson(obj))
Expand Down
13 changes: 10 additions & 3 deletions models/aggregated_block_feed/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ import (
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/composite_redstone_price_feed"
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/curve_price_feed"
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/redstone_price_feed"
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/single_asset_feed"
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/yearn_price_feed"
)

func NewQueryPriceFeed(token, oracle string, pfType string, discoveredAt int64, client core.ClientI, repo ds.RepositoryI, pfVersion schemas.PFVersion) ds.QueryPriceFeedI {
func NewQueryPriceFeed(token, oracle string, pfType string, discoveredAt int64, client core.ClientI, repo ds.RepositoryI, pfVersion schemas.PFVersion, underlyingFeeds []string) ds.QueryPriceFeedI {
switch pfType {
case ds.RedStonePF:
return redstone_price_feed.NewRedstonePriceFeed(token, oracle, pfType, discoveredAt, client, repo, pfVersion)
case ds.CurvePF:
return curve_price_feed.NewCurvePriceFeed(token, oracle, pfType, discoveredAt, client, repo, pfVersion)
case ds.CompositeRedStonePF:
return composite_redstone_price_feed.NewRedstonePriceFeed(token, oracle, pfType, discoveredAt, client, repo, pfVersion)
case ds.YearnPF, ds.SingleAssetPF:
case ds.YearnPF:
return yearn_price_feed.NewYearnPriceFeed(token, oracle, pfType, discoveredAt, client, repo, pfVersion)
case ds.SingleAssetPF:
return single_asset_feed.NewSingleAsset(token, oracle, pfType, discoveredAt, client, repo, pfVersion, underlyingFeeds)
default:
return nil
}
Expand All @@ -33,8 +36,10 @@ func NewQueryPriceFeedFromAdapter(adapter *ds.SyncAdapter) ds.QueryPriceFeedI {
case ds.CompositeRedStonePF:
return composite_redstone_price_feed.NewRedstonePriceFeedFromAdapter(adapter)
// return curve_price_feed.NewCurvePriceFeedFromAdapter(adapter)
case ds.YearnPF, ds.SingleAssetPF:
case ds.YearnPF:
return yearn_price_feed.NewYearnPriceFeedFromAdapter(adapter)
case ds.SingleAssetPF:
return single_asset_feed.NewSingleAssetFromAdapter(adapter)
default:
return nil
}
Expand All @@ -49,6 +54,8 @@ func FromAdapter(obj ds.SyncAdapterI) ds.QueryPriceFeedI {
return adapter
case *composite_redstone_price_feed.CompositeRedStonePriceFeed:
return adapter
case *single_asset_feed.SingleAssetFeed:
return adapter
default:
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions models/aggregated_block_feed/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (mdl *AQFWrapper) GetQueryFeeds() []ds.QueryPriceFeedI {
return feeds
}

func (mdl *AQFWrapper) AddFeedOrToken(token, oracle string, pfType string, discoveredAt int64, pfVersion schemas.PFVersion) {
func (mdl *AQFWrapper) AddFeedOrToken(token, oracle string, pfType string, discoveredAt int64, pfVersion schemas.PFVersion, underlyingFeeds []string) {
log.Infof("Add new %s:pfversion(%d) for token(%s): %s discovered at %d", pfType, pfVersion, token, oracle, discoveredAt)
// MAINNET: yearn yvUSDC has changed over time, previous token was 0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9(only added in gearbox v1 priceOracle) and 0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE, so we can ignore 0xc1 yvUSDC token dependency
if token != "0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9" {
Expand All @@ -82,7 +82,7 @@ func (mdl *AQFWrapper) AddFeedOrToken(token, oracle string, pfType string, disco
if mdl.QueryFeeds[oracle] != nil {
mdl.QueryFeeds[oracle].AddToken(token, discoveredAt, pfVersion)
} else {
mdl.AddQueryPriceFeed(NewQueryPriceFeed(token, oracle, pfType, discoveredAt, mdl.Client, mdl.Repo, pfVersion))
mdl.AddQueryPriceFeed(NewQueryPriceFeed(token, oracle, pfType, discoveredAt, mdl.Client, mdl.Repo, pfVersion, underlyingFeeds))
// MAINNET: old yvUSDC added on gearbox v1
if token == "0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9" {
mdl.QueryFeeds[oracle].DisableToken(token, 13856183, pfVersion) // new yvUSDC added on gearbox v1
Expand Down
112 changes: 112 additions & 0 deletions models/aggregated_block_feed/single_asset_feed/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package single_asset_feed

import (
"encoding/hex"

"github.com/Gearbox-protocol/sdk-go/artifacts/multicall"
"github.com/Gearbox-protocol/sdk-go/artifacts/redstone"
"github.com/Gearbox-protocol/sdk-go/core"
"github.com/Gearbox-protocol/sdk-go/core/schemas"
"github.com/Gearbox-protocol/sdk-go/log"
"github.com/Gearbox-protocol/third-eye/ds"
"github.com/Gearbox-protocol/third-eye/models/aggregated_block_feed/base_price_feed"
"github.com/ethereum/go-ethereum/common"
)

type SingleAssetFeed struct {
*base_price_feed.BasePriceFeed
}

func NewSingleAsset(token, oracle string, pfType string, discoveredAt int64, client core.ClientI, repo ds.RepositoryI, pfVersion schemas.PFVersion, underlyingFeeds []string) *SingleAssetFeed {
adapter := base_price_feed.NewBasePriceFeed(token, oracle, pfType, discoveredAt, client, repo, pfVersion)
return NewSingleAssetFromAdapter(adapter.SyncAdapter)
}

func NewSingleAssetFromAdapter(adapter *ds.SyncAdapter) *SingleAssetFeed {
return &SingleAssetFeed{
BasePriceFeed: base_price_feed.NewBasePriceFeedFromAdapter(adapter),
}
}

func (mdl *SingleAssetFeed) GetUnderlyings() (ans []string) {
underlyings := mdl.Details["underlyings"]
log.Info("here", underlyings)
if underlyings != nil {
_underlyings, ok := underlyings.([]interface{})
if ok {
for _, entry := range _underlyings {
ans = append(ans, entry.(string))
}
}
}
return
}

func (mdl *SingleAssetFeed) GetCalls(blockNum int64) (calls []multicall.Multicall2Call, isQueryable bool) {
updateABI := core.GetAbi("UpdatePriceFeed")
for _, entry := range mdl.GetUnderlyings() {
log.Info("here2", entry)
contract, err := redstone.NewRedstone(common.HexToAddress(entry), mdl.Client)
log.CheckFatal(err)
var tokenDetails *core.RedStonePF
if _, ok := mdl.DetailsDS.Info[entry]; ok {
tokenDetails = mdl.DetailsDS.Info[entry]
} else if dataIdBytes, err := contract.DataFeedId(nil); err == nil {
dataId := func() string {
var s []byte
for _, b := range dataIdBytes {
if b != 0 {
s = append(s, b)
} else {
break
}
}
return string(s)

}()
//
signThreshold, err := contract.GetUniqueSignersThreshold(nil)
log.CheckFatal(err)
token, err := contract.Token(nil)
log.CheckFatal(err)
tokenDetails = &core.RedStonePF{
Type: 15,
DataServiceId: "redstone-primary-prod",
DataId: dataId,
SignersThreshold: int(signThreshold),
UnderlyingToken: token,
}
mdl.DetailsDS.Info[entry] = tokenDetails
}
if tokenDetails != nil {
pod := mdl.Repo.GetRedStonemgr().GetPodSignWithRedstoneToken(int64(mdl.Repo.SetAndGetBlock(blockNum).Timestamp), *tokenDetails)
update, err := updateABI.Pack("updatePrice", pod.CallData)
log.CheckFatal(err)
calls = append(calls, multicall.Multicall2Call{
Target: common.HexToAddress(entry),
CallData: update,
})
}
}
b, err := hex.DecodeString("feaf968c")
log.CheckFatal(err)
calls = append(calls, multicall.Multicall2Call{
Target: common.HexToAddress(mdl.Address),
CallData: b,
})
return calls, true
}

// same as query price feed
// func (*YearnPriceFeed) GetCalls(blockNum int64) (calls []multicall.Multicall2Call, isQueryable bool) {

func (mdl *SingleAssetFeed) ProcessResult(blockNum int64, results []multicall.Multicall2Result, force ...bool) *schemas.PriceFeed {
if !results[0].Success {
log.Warnf("Can't get latestRounData for YearnModule in AQFWrapper for %s(%s) at %d",
mdl.GetDetailsByKey("pfType"), mdl.GetAddress(), blockNum)
return nil
//
}
isPriceInUSD := mdl.GetVersion().IsPriceInUSD()
return base_price_feed.ParseQueryRoundData(results[0].ReturnData, isPriceInUSD, mdl.GetAddress(), blockNum)
}
47 changes: 26 additions & 21 deletions models/price_oracle/on_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (mdl *PriceOracle) OnLog(txLog types.Log) {
},
})

priceFeedType, bounded, err := mdl.checkPriceFeedContract(blockNum, oracle, token)
priceFeedType, underlyingFeeds, bounded, err := mdl.checkPriceFeedContract(blockNum, oracle, token)
if err != nil {
log.Fatalf("Oracle %s, err: %s, blockNum %d", oracle, err, blockNum)
}
Expand Down Expand Up @@ -105,6 +105,7 @@ func (mdl *PriceOracle) OnLog(txLog types.Log) {
Version: mdl.GetVersion(),
Reserve: isReverse,
FeedType: priceFeedType,
Underlyings: underlyingFeeds,
}, bounded)
default:
log.Fatal("Unknown PriceFeed type", priceFeedType)
Expand All @@ -115,13 +116,13 @@ func (mdl *PriceOracle) OnLog(txLog types.Log) {
// YearnPF covers LIDO, AAVE, COMPOUND, YEARN, ERC4626, Balancer(Stable, weighted)
// CurvePF covers curve and convex
// ChainlinkPF cover chainlink
func (mdl *PriceOracle) checkPriceFeedContract(discoveredAt int64, oracle, token string) (string, bool, error) { // type, bounded , error
func (mdl *PriceOracle) checkPriceFeedContract(discoveredAt int64, oracle, token string) (string, []string, bool, error) { // type, bounded , error
if oracle == "0xE26FB07da646138553f635c94E2a345270240e30" { // for goerli , the chainlink bounded oracle doesn't have phaseId method // LUSD price oracle
return ds.ChainlinkPriceFeed, true, nil
return ds.ChainlinkPriceFeed, nil, true, nil
}
pfContract, err := priceFeed.NewPriceFeed(common.HexToAddress(oracle), mdl.Client)
if err != nil {
return ds.UnknownPF, false, err
return ds.UnknownPF, nil, false, err
}
opts := &bind.CallOpts{
BlockNumber: big.NewInt(discoveredAt),
Expand All @@ -134,23 +135,25 @@ func (mdl *PriceOracle) checkPriceFeedContract(discoveredAt int64, oracle, token
if mdl.GetVersion().MoreThanEq(core.NewVersion(300)) {
return mdl.V3PriceFeedType(opts, oracle, token)
} else {
return mdl.v2PriceFeedType(opts, oracle)
a, b, c := mdl.v2PriceFeedType(opts, oracle)
return a, nil, b, c
}
}
} else { //chainlink description
yearnContract, err := yearnPriceFeed.NewYearnPriceFeed(common.HexToAddress(oracle), mdl.Client)
log.CheckFatal(err)
description, err := yearnContract.Description(opts)
return ds.ChainlinkPriceFeed,
nil,
(err == nil) && strings.Contains(string(description), "Bounded"),
nil
}
return ds.UnknownPF, false, fmt.Errorf("PriceFeed type not found")
return ds.UnknownPF, nil, false, fmt.Errorf("PriceFeed type not found")
}

// https://github.com/Gearbox-protocol/integrations-v2/tree/faa9cfd4921c62165782dcdc196ff5a0c0e6075d/contracts/oracles
// https://github.com/Gearbox-protocol/oracles-v3/tree/2ac6d1ba1108df949222084791699d821096bc8c/contracts/oracles
func (mdl *PriceOracle) V3PriceFeedType(opts *bind.CallOpts, oracle, token string) (string, bool, error) {
func (mdl *PriceOracle) V3PriceFeedType(opts *bind.CallOpts, oracle, token string) (string, []string, bool, error) {
data, err := core.CallFuncWithExtraBytes(mdl.Client, "3fd0875f", common.HexToAddress(oracle), 0, nil) // priceFeedType
if err != nil {
{ // redstone feed without price on demand doesn't have priceFeedType method.
Expand All @@ -162,7 +165,7 @@ func (mdl *PriceOracle) V3PriceFeedType(opts *bind.CallOpts, oracle, token strin
} else {
description = strings.ToLower(string(description))
if strings.Contains(description, "redstone") {
return ds.CurvePF, false, nil
return ds.CurvePF, nil, false, nil
} else {
log.Fatal(oracle, token, "priceFeedType failed: ", description, err)
}
Expand Down Expand Up @@ -205,38 +208,40 @@ func (mdl *PriceOracle) V3PriceFeedType(opts *bind.CallOpts, oracle, token strin
}()
switch pf0Type {
case core.V3_REDSTONE_ORACLE:
return ds.CompositeRedStonePF, false, nil
return ds.CompositeRedStonePF, nil, false, nil
case core.V3_CHAINLINK_ORACLE:
return ds.CompositeChainlinkPF, false, nil
return ds.CompositeChainlinkPF, nil, false, nil
default:
return ds.CurvePF, false, nil
return ds.CurvePF, nil, false, nil
}
}
case core.V3_YEARN_ORACLE:
return ds.YearnPF, false, nil
return ds.YearnPF, nil, false, nil
case core.V3_CHAINLINK_ORACLE:
return ds.ChainlinkPriceFeed, true, nil
return ds.ChainlinkPriceFeed, nil, true, nil
case core.V3_CURVE_USD_ORACLE, core.V3_CURVE_CRYPTO_ORACLE, // usd and crypto
core.V3_CURVE_2LP_ORACLE, core.V3_CURVE_3LP_ORACLE, core.V3_CURVE_4LP_ORACLE: // 2lp,3lp, 4lp
return ds.CurvePF, false, nil
return ds.CurvePF, nil, false, nil
case core.V3_ZERO_ORACLE:
return ds.ZeroPF, false, nil
return ds.ZeroPF, nil, false, nil
// SingleAssetLPPriceFeed
case core.V3_WSTETH_ORACLE, core.V3_WRAPPED_AAVE_V2_ORACLE, // lido, aave,
core.V3_BALANCER_STABLE_LP_ORACLE, core.V3_BALANCER_WEIGHTED_LP_ORACLE, // balancer
core.V3_COMPOUND_V2_ORACLE, // compounder
core.V3_MELLOW_LRT_ORACLE, // mellow is SingleAssetPriceFeed
core.V3_PENDLE_PT_TWAP_ORACLE,
core.V3_COMPOUND_V2_ORACLE, // compounder
core.V3_MELLOW_LRT_ORACLE, // mellow is SingleAssetPriceFeed
core.V3_ERC4626_VAULT_ORACLE: // erc4626
return ds.SingleAssetPF, false, nil
return ds.SingleAssetPF, nil, false, nil
case core.V3_PENDLE_PT_TWAP_ORACLE:
underlying, err := core.CallFuncWithExtraBytes(mdl.Client, "741bef1a", common.HexToAddress(oracle), 0, nil) // priceFeed
return ds.SingleAssetPF, []string{common.BytesToAddress(underlying).Hex()}, false, err
case core.V3_REDSTONE_ORACLE:
return ds.RedStonePF, false, nil
return ds.RedStonePF, nil, false, nil
default:
yearnContract, err := yearnPriceFeed.NewYearnPriceFeed(common.HexToAddress(oracle), mdl.Client)
log.CheckFatal(err)
description, err := yearnContract.Description(opts)
log.CheckFatal(err)
return ds.UnknownPF, false, fmt.Errorf("unknown v3 pfType %v, oracle: %s token: %s, description: %s", pfType, oracle, token, description)
return ds.UnknownPF, nil, false, fmt.Errorf("unknown v3 pfType %v, oracle: %s token: %s, description: %s", pfType, oracle, token, description)
}
}

Expand Down
1 change: 1 addition & 0 deletions repository/handlers/token_oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ func (repo *TokenOracleRepo) AddNewPriceOracleEvent(newTokenOracle *schemas.Toke
newTokenOracle.FeedType,
newTokenOracle.BlockNumber,
pfVersion,
newTokenOracle.Underlyings,
)
}
case ds.ChainlinkPriceFeed:
Expand Down
Loading

0 comments on commit b610477

Please sign in to comment.