diff --git a/calc/entry_price.go b/calc/entry_price.go index a6d87d70e..a0504db4f 100644 --- a/calc/entry_price.go +++ b/calc/entry_price.go @@ -14,13 +14,7 @@ import ( type PriceDS struct { CurrentPrice float64 `json:"closePrice"` TradingToken string `json:"tradingToken,omitempty"` - QuoteToken string `json:"quoteToken,omitempty"` -} - -func (session *PriceDS) SetCurrentPrice(tradingToken, quoteToken string, price float64) { - session.TradingToken = tradingToken - session.QuoteToken = quoteToken - session.CurrentPrice = price + BaseToken string `json:"quoteToken,omitempty"` } type EntryPriceI interface { @@ -58,34 +52,34 @@ func loadSymToAddrStore(chainId int64) { } } -func CalcCurrentPriceBySession(session EntryPriceI, chainId int64, store tokenI) { - cBal := new(big.Int).Add( - toBigInt(session.GetCollateralInUnderlying(), store.GetToken(session.GetUnderlyingToken()).Decimals), - session.GetBorrowedAmount(), - ) - tradingToken, quoteToken, currentPrice, err := CalcCurrentPrice( - session.GetBalances(), - session.GetUnderlyingToken(), - cBal, - chainId, - store, - ) - if err != nil { - return - } - session.SetCurrentPrice(tradingToken, quoteToken, currentPrice) -} -func CalcCurrentPrice(bal core.DBBalanceFormat, - cToken string, cBal *big.Int, chainId int64, store tokenI) (string, string, float64, error) { - loadSymToAddrStore(chainId) - // - // - if _, ok := bal[cToken]; ok { - cBal = new(big.Int).Sub(cBal, bal[cToken].BI.Convert()) - } - // - return getCurrentPrice(bal, store, cToken, cBal) -} +// func CalcCurrentPriceBySession(session EntryPriceI, chainId int64, store tokenI) { +// cBal := new(big.Int).Add( +// toBigInt(session.GetCollateralInUnderlying(), store.GetToken(session.GetUnderlyingToken()).Decimals), +// session.GetBorrowedAmount(), +// ) +// tradingToken, quoteToken, currentPrice, err := CalcCurrentPrice( +// session.GetBalances(), +// session.GetUnderlyingToken(), +// cBal, +// chainId, +// store, +// ) +// if err != nil { +// return +// } +// session.SetCurrentPrice(tradingToken, quoteToken, currentPrice) +// } +// func CalcCurrentPrice(bal core.DBBalanceFormat, +// cToken string, cBal *big.Int, chainId int64, store tokenI) (string, string, float64, error) { +// loadSymToAddrStore(chainId) +// // +// // +// if _, ok := bal[cToken]; ok { +// cBal = new(big.Int).Sub(cBal, bal[cToken].BI.Convert()) +// } +// // +// return getCurrentPrice(bal, store, cToken, cBal) +// } func getCurrentPrice(bal core.DBBalanceFormat, store tokenI, cToken string, cBal *big.Int) (string, string, float64, error) { otherToken, otherAmount, ok := singleEntryPriceToken(bal, cToken) @@ -112,6 +106,15 @@ func getCurrentPrice(bal core.DBBalanceFormat, store tokenI, cToken string, cBal return tradingToken, baseToken, currentPrice, nil } +func TradingAndBaseTokens(bal core.DBBalanceFormat, cToken string) (tradingToken, baseToken string) { + otherToken, _, ok := singleEntryPriceToken(bal, cToken) + if !ok { + return "", "" + } + + return tradingAndBase(otherToken, cToken) +} + // trading priority is higher than base func tradingAndBase(a, b string) (trading, base string) { if priority(a) > priority(b) { diff --git a/calc/entry_price_test.go b/calc/entry_price_test.go deleted file mode 100644 index 60ea3cef2..000000000 --- a/calc/entry_price_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package calc - -import ( - "math/big" - "testing" - - "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/sdk-go/utils" -) - -type session struct { - balances core.DBBalanceFormat - borrowedAmount *big.Int - collateral core.JsonBigIntMap - underlying string - // - tradingToken string - quoteToken string - currentPrice float64 -} - -func (s session) GetBalances() core.DBBalanceFormat { - return s.balances -} -func (s session) GetBorrowedAmount() *big.Int { - return s.borrowedAmount -} -func (s session) GetCollateralInUnderlying() interface{} { - return s.collateral[s.underlying] -} -func (s session) GetUnderlyingToken() string { - return s.underlying -} -func (s *session) SetCurrentPrice(tradingToken, quoteToken string, currentPrice float64) { - s.tradingToken = tradingToken - s.quoteToken = quoteToken - s.currentPrice = currentPrice -} - -type dStore struct { - tokens map[string]*schemas.Token -} - -func (d dStore) GetToken(token string) *schemas.Token { - return d.tokens[token] -} -func TestEntryPriceForLong(t *testing.T) { - log.SetTestLogging(t) - usdc := "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" - tradingToken := utils.RandomAddr() - sess := &session{ - balances: map[string]core.DBTokenBalance{tradingToken: {IsEnabled: true, BI: (*core.BigInt)(utils.GetExpInt(18))}}, - borrowedAmount: new(big.Int).Mul(big.NewInt(3), utils.GetExpInt(6+3)), - collateral: core.JsonBigIntMap{usdc: (*core.BigInt)(utils.GetExpInt(6 + 3))}, - underlying: usdc, - } - CalcCurrentPriceBySession(sess, 1, dStore{ - tokens: map[string]*schemas.Token{ - usdc: {Decimals: 6}, - tradingToken: {Decimals: 18}, - }, - }) - - if sess.tradingToken != tradingToken { - t.Fatal("trading token is not set", sess.tradingToken) - } - if sess.currentPrice != 4000 { - t.Fatal("entry price is wrong", sess.currentPrice) - } -} - -func BenchmarkFooer(b *testing.B) { - for i := 0; i < b.N; i++ { - for j := 0; j < i; j++ { - _ = 1 + 1 - } - } -} diff --git a/pkg/priceFetcher/1inch_oracle.go b/pkg/priceFetcher/1inch_oracle.go index 40851b60f..eb4ce981f 100644 --- a/pkg/priceFetcher/1inch_oracle.go +++ b/pkg/priceFetcher/1inch_oracle.go @@ -6,8 +6,10 @@ import ( "fmt" "math/big" "net/http" + "strings" "github.com/Gearbox-protocol/sdk-go/artifacts/multicall" + "github.com/Gearbox-protocol/sdk-go/calc" "github.com/Gearbox-protocol/sdk-go/core" "github.com/Gearbox-protocol/sdk-go/log" "github.com/Gearbox-protocol/sdk-go/utils" @@ -57,7 +59,14 @@ type DecimalStoreI interface { GetDecimalsForList([]common.Address) } -func New1InchOracle(client core.ClientI, chainId int64, inchOracle common.Address, tStore DecimalStoreI, dataStrings ...string) *OneInchOracle { +func JsonnetStringInchConfig(syms []core.Symbol) string { + var subPhrase []string + for _, sym := range syms { + subPhrase = append(subPhrase, fmt.Sprintf(`'%s'`, sym)) + } + return fmt.Sprintf(`{baseTokens: [%s]}`, strings.Join(subPhrase, ",")) +} +func New1InchOracle(client core.ClientI, chainId int64, tStore DecimalStoreI, dataStrings ...string) *OneInchOracle { calc := &OneInchOracle{} // get 1inch jsonnet data := func() string { @@ -77,7 +86,7 @@ func New1InchOracle(client core.ClientI, chainId int64, inchOracle common.Addres // delete ETH as 0xee address can't be used for getting symbol in token_store.go delete(calc.symToAddr.Tokens, "ETH") // - calc.inchOracle = inchOracle + calc.inchOracle = get1InchAddress(chainId) calc.client = client calc.setCrvCallLen() @@ -86,6 +95,15 @@ func New1InchOracle(client core.ClientI, chainId int64, inchOracle common.Addres return calc } +func get1InchAddress(chainId int64) common.Address { + switch chainId { + case 1, 7878, 1337: + return common.HexToAddress("0x07D91f5fb9Bf7798734C3f606dB065549F6893bb") + } + log.Fatal("Can't get the inch oracle for", chainId) + return core.NULL_ADDR +} + func (calc *OneInchOracle) setCrvCallLen() { var crvLen int for _, details := range calc.CrvTokens { @@ -372,3 +390,61 @@ func (calc OneInchOracle) processCrvResults(results []multicall.Multicall2Result ind++ } } + +func (o *OneInchOracle) GetCurrentPriceAtBlockNum(blockNum int64, bal core.DBBalanceFormat, underlying string) float64 { + tradingToken, baseToken := calc.TradingAndBaseTokens(bal, underlying) + if tradingToken == "" { + return 0 + } + // + prices := map[string]*core.BigInt{} + // + { // getting price via multicall + inchOracle := get1InchAddress(core.GetChainId(o.client)) + tokens := []common.Address{common.HexToAddress(tradingToken), common.HexToAddress(baseToken)} + usdc := o.symToAddr.Tokens["USDC"] + // + pfABI := core.GetAbi("1InchOracle") + calls := []multicall.Multicall2Call{} + for _, token := range tokens { + data, err := pfABI.Pack("getRate", token, usdc, false) + log.CheckFatal(err) + calls = append(calls, multicall.Multicall2Call{ + Target: inchOracle, + CallData: data, + }) + } + results := core.MakeMultiCall(o.client, blockNum, false, calls) + for ind, entry := range results { + tokenAddr := tokens[ind] + if entry.Success { + price := new(big.Int).SetBytes(entry.ReturnData) + // for usdt = 18-6-2 = 10 + // for wbtc = 18-8-2 = 8 + // for gusd = 18-2-2= 14 + normalizeDecimal := 18 - o.decimals.GetDecimals(tokenAddr) - 2 + price = utils.GetInt64(price, normalizeDecimal) + prices[tokenAddr.Hex()] = (*core.BigInt)(price) + } else if usdc == tokenAddr { + prices[tokenAddr.Hex()] = (*core.BigInt)(big.NewInt(1000_000_00)) + } + } + } + return GetTradingPriceFrom1Inch(prices, tradingToken, baseToken) +} + +func GetTradingPriceFrom1Inch(prices map[string]*core.BigInt, tradingToken, baseToken string) float64 { + getPrice := func(token string) *big.Int { + p := prices[token] + if p == nil { + return new(big.Int) + } + return p.Convert() + } + tradingPrice := utils.GetFloat64Decimal(getPrice(tradingToken), 8) + basePrice := utils.GetFloat64Decimal(getPrice(baseToken), 8) + if tradingPrice == 0 || basePrice == 0 { + return 0 + } + return tradingPrice / basePrice +} diff --git a/pkg/priceFetcher/1inch_test.go b/pkg/priceFetcher/1inch_test.go index bf2129239..25aaa1b22 100644 --- a/pkg/priceFetcher/1inch_test.go +++ b/pkg/priceFetcher/1inch_test.go @@ -31,9 +31,7 @@ func TestSpotPriceStore(t *testing.T) { expectedTokenPrices := map[string]string{} utils.ReadJsonAndSetInterface("inputs/spot_price_test.json", &expectedTokenPrices) tStore := getDecimalStore(client, expectedTokenPrices, blockNumber, t) - inchOracle := common.HexToAddress("0x07D91f5fb9Bf7798734C3f606dB065549F6893bb") // 1inch oracle - // - store := New1InchOracle(client, 1, inchOracle, tStore) + store := New1InchOracle(client, 1, tStore) calls := store.GetCalls() // results := core.MakeMultiCall(client, blockNumber, false, calls)