Governor should handle duplicate coin gecko ids
This commit is contained in:
parent
09b33552df
commit
5ca2faa9a3
|
@ -105,7 +105,7 @@ type ChainGovernor struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
tokens map[tokenKey]*tokenEntry
|
tokens map[tokenKey]*tokenEntry
|
||||||
tokensByCoinGeckoId map[string]*tokenEntry
|
tokensByCoinGeckoId map[string][]*tokenEntry
|
||||||
chains map[vaa.ChainID]*chainEntry
|
chains map[vaa.ChainID]*chainEntry
|
||||||
msgsToPublish []*common.MessagePublication
|
msgsToPublish []*common.MessagePublication
|
||||||
dayLengthInMinutes int
|
dayLengthInMinutes int
|
||||||
|
@ -122,7 +122,7 @@ func NewChainGovernor(
|
||||||
db: db,
|
db: db,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
tokens: make(map[tokenKey]*tokenEntry),
|
tokens: make(map[tokenKey]*tokenEntry),
|
||||||
tokensByCoinGeckoId: make(map[string]*tokenEntry),
|
tokensByCoinGeckoId: make(map[string][]*tokenEntry),
|
||||||
chains: make(map[vaa.ChainID]*chainEntry),
|
chains: make(map[vaa.ChainID]*chainEntry),
|
||||||
env: env,
|
env: env,
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,17 @@ func (gov *ChainGovernor) initConfig() error {
|
||||||
te := &tokenEntry{cfgPrice: cfgPrice, price: initialPrice, decimals: decimals, symbol: ct.symbol, coinGeckoId: ct.coinGeckoId, token: key}
|
te := &tokenEntry{cfgPrice: cfgPrice, price: initialPrice, decimals: decimals, symbol: ct.symbol, coinGeckoId: ct.coinGeckoId, token: key}
|
||||||
te.updatePrice()
|
te.updatePrice()
|
||||||
|
|
||||||
|
gov.tokens[key] = te
|
||||||
|
|
||||||
|
// Multiple tokens can share a CoinGecko price, so we keep an array of tokens per CoinGecko ID.
|
||||||
|
cge, cgExists := gov.tokensByCoinGeckoId[te.coinGeckoId]
|
||||||
|
if !cgExists {
|
||||||
|
gov.tokensByCoinGeckoId[te.coinGeckoId] = []*tokenEntry{te}
|
||||||
|
} else {
|
||||||
|
cge = append(cge, te)
|
||||||
|
gov.tokensByCoinGeckoId[te.coinGeckoId] = cge
|
||||||
|
}
|
||||||
|
|
||||||
gov.logger.Info("cgov: will monitor token:", zap.Stringer("chain", key.chain),
|
gov.logger.Info("cgov: will monitor token:", zap.Stringer("chain", key.chain),
|
||||||
zap.Stringer("addr", key.addr),
|
zap.Stringer("addr", key.addr),
|
||||||
zap.String("symbol", te.symbol),
|
zap.String("symbol", te.symbol),
|
||||||
|
@ -193,9 +204,6 @@ func (gov *ChainGovernor) initConfig() error {
|
||||||
zap.Int64("decimals", dec),
|
zap.Int64("decimals", dec),
|
||||||
zap.Int64("origDecimals", ct.decimals),
|
zap.Int64("origDecimals", ct.decimals),
|
||||||
)
|
)
|
||||||
|
|
||||||
gov.tokens[key] = te
|
|
||||||
gov.tokensByCoinGeckoId[te.coinGeckoId] = te
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(gov.tokens) == 0 {
|
if len(gov.tokens) == 0 {
|
||||||
|
|
|
@ -109,13 +109,13 @@ func (gov *ChainGovernor) queryCoinGecko() {
|
||||||
gov.mutex.Lock()
|
gov.mutex.Lock()
|
||||||
defer gov.mutex.Unlock()
|
defer gov.mutex.Unlock()
|
||||||
|
|
||||||
localTokenMap := make(map[string]*tokenEntry)
|
localTokenMap := make(map[string][]*tokenEntry)
|
||||||
for coinGeckoId, te := range gov.tokensByCoinGeckoId {
|
for coinGeckoId, cge := range gov.tokensByCoinGeckoId {
|
||||||
localTokenMap[coinGeckoId] = te
|
localTokenMap[coinGeckoId] = cge
|
||||||
}
|
}
|
||||||
|
|
||||||
for coinGeckoId, data := range result {
|
for coinGeckoId, data := range result {
|
||||||
te, exists := gov.tokensByCoinGeckoId[coinGeckoId]
|
cge, exists := gov.tokensByCoinGeckoId[coinGeckoId]
|
||||||
if exists {
|
if exists {
|
||||||
price, ok := data.(map[string]interface{})["usd"].(float64)
|
price, ok := data.(map[string]interface{})["usd"].(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -123,18 +123,21 @@ func (gov *ChainGovernor) queryCoinGecko() {
|
||||||
// By continuing, we leave this one in the local map so the price will get reverted below.
|
// By continuing, we leave this one in the local map so the price will get reverted below.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
te.coinGeckoPrice = big.NewFloat(price)
|
|
||||||
te.updatePrice()
|
|
||||||
te.priceTime = now
|
|
||||||
|
|
||||||
gov.logger.Info("cgov: updated price",
|
for _, te := range cge {
|
||||||
zap.String("symbol", te.symbol),
|
te.coinGeckoPrice = big.NewFloat(price)
|
||||||
zap.String("coinGeckoId",
|
te.updatePrice()
|
||||||
te.coinGeckoId),
|
te.priceTime = now
|
||||||
zap.Stringer("price", te.price),
|
|
||||||
zap.Stringer("cfgPrice", te.cfgPrice),
|
gov.logger.Info("cgov: updated price",
|
||||||
zap.Stringer("coinGeckoPrice", te.coinGeckoPrice),
|
zap.String("symbol", te.symbol),
|
||||||
)
|
zap.String("coinGeckoId",
|
||||||
|
te.coinGeckoId),
|
||||||
|
zap.Stringer("price", te.price),
|
||||||
|
zap.Stringer("cfgPrice", te.cfgPrice),
|
||||||
|
zap.Stringer("coinGeckoPrice", te.coinGeckoPrice),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
delete(localTokenMap, coinGeckoId)
|
delete(localTokenMap, coinGeckoId)
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,8 +146,29 @@ func (gov *ChainGovernor) queryCoinGecko() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(localTokenMap) != 0 {
|
if len(localTokenMap) != 0 {
|
||||||
for _, te := range localTokenMap {
|
for _, lcge := range localTokenMap {
|
||||||
gov.logger.Error("cgov: did not receive a CoinGecko response for symbol, reverting to configured price",
|
for _, te := range lcge {
|
||||||
|
gov.logger.Error("cgov: did not receive a CoinGecko response for symbol, reverting to configured price",
|
||||||
|
zap.String("symbol", te.symbol),
|
||||||
|
zap.String("coinGeckoId",
|
||||||
|
te.coinGeckoId),
|
||||||
|
zap.Stringer("cfgPrice", te.cfgPrice),
|
||||||
|
)
|
||||||
|
|
||||||
|
te.price = te.cfgPrice
|
||||||
|
// Don't update the timestamp so we'll know when we last received an update from CoinGecko.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gov *ChainGovernor) revertAllPrices() {
|
||||||
|
gov.mutex.Lock()
|
||||||
|
defer gov.mutex.Unlock()
|
||||||
|
|
||||||
|
for _, cge := range gov.tokensByCoinGeckoId {
|
||||||
|
for _, te := range cge {
|
||||||
|
gov.logger.Error("cgov: reverting to configured price",
|
||||||
zap.String("symbol", te.symbol),
|
zap.String("symbol", te.symbol),
|
||||||
zap.String("coinGeckoId",
|
zap.String("coinGeckoId",
|
||||||
te.coinGeckoId),
|
te.coinGeckoId),
|
||||||
|
@ -157,23 +181,6 @@ func (gov *ChainGovernor) queryCoinGecko() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gov *ChainGovernor) revertAllPrices() {
|
|
||||||
gov.mutex.Lock()
|
|
||||||
defer gov.mutex.Unlock()
|
|
||||||
|
|
||||||
for _, te := range gov.tokensByCoinGeckoId {
|
|
||||||
gov.logger.Error("cgov: reverting to configured price",
|
|
||||||
zap.String("symbol", te.symbol),
|
|
||||||
zap.String("coinGeckoId",
|
|
||||||
te.coinGeckoId),
|
|
||||||
zap.Stringer("cfgPrice", te.cfgPrice),
|
|
||||||
)
|
|
||||||
|
|
||||||
te.price = te.cfgPrice
|
|
||||||
// Don't update the timestamp so we'll know when we last received an update from CoinGecko.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should use the max(coinGeckoPrice, configuredPrice) as our price for computing notional value.
|
// We should use the max(coinGeckoPrice, configuredPrice) as our price for computing notional value.
|
||||||
func (te tokenEntry) updatePrice() {
|
func (te tokenEntry) updatePrice() {
|
||||||
if (te.coinGeckoPrice == nil) || (te.coinGeckoPrice.Cmp(te.cfgPrice) < 0) {
|
if (te.coinGeckoPrice == nil) || (te.coinGeckoPrice.Cmp(te.cfgPrice) < 0) {
|
||||||
|
|
|
@ -78,7 +78,13 @@ func (gov *ChainGovernor) setTokenForTesting(tokenChainID vaa.ChainID, tokenAddr
|
||||||
key := tokenKey{chain: vaa.ChainID(tokenChainID), addr: tokenAddr}
|
key := tokenKey{chain: vaa.ChainID(tokenChainID), addr: tokenAddr}
|
||||||
te := &tokenEntry{cfgPrice: bigPrice, price: bigPrice, decimals: decimals, symbol: symbol, coinGeckoId: symbol, token: key}
|
te := &tokenEntry{cfgPrice: bigPrice, price: bigPrice, decimals: decimals, symbol: symbol, coinGeckoId: symbol, token: key}
|
||||||
gov.tokens[key] = te
|
gov.tokens[key] = te
|
||||||
gov.tokensByCoinGeckoId[symbol] = te
|
cge, cgExists := gov.tokensByCoinGeckoId[te.coinGeckoId]
|
||||||
|
if !cgExists {
|
||||||
|
gov.tokensByCoinGeckoId[te.coinGeckoId] = []*tokenEntry{te}
|
||||||
|
} else {
|
||||||
|
cge = append(cge, te)
|
||||||
|
gov.tokensByCoinGeckoId[te.coinGeckoId] = cge
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue