From 02f7dbe31eaed0f576169c052a4fba74d5bd0751 Mon Sep 17 00:00:00 2001 From: dsudit01 <79417718+dsudit01@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:54:22 +0530 Subject: [PATCH] supply apy for tbills --- config/fpi.go | 21 +++++++++ config/jsons/fpi_mainnet.json | 15 ++++-- config/tokens.go | 21 +++++---- queryengine/contracts/utils.go | 86 +++++++++++++++++++++++++++------- 4 files changed, 115 insertions(+), 28 deletions(-) diff --git a/config/fpi.go b/config/fpi.go index 282b4d9..3dba1b2 100644 --- a/config/fpi.go +++ b/config/fpi.go @@ -103,6 +103,27 @@ func getCTokenContractCalls() []Contract { {}, }, }) + + // check token tags and add calls accordingly + if token.Tags != nil { + for _, tag := range token.Tags { + if tag == "hashnote" { + calls = append(calls, Contract{ + Name: token.Symbol + "latestRoundDetails", + Address: "0x1d18c02bC80b1921255E71cF2939C03258d75470", + Keys: []string{ + "cTokens:" + token.Address + ":latestRoundDetails", + }, + Methods: []string{ + "latestRoundDetails()(uint80,uint256,uint256,uint256,uint256)", + }, + Args: [][]interface{}{ + {}, + }, + }) + } + } + } } return calls diff --git a/config/jsons/fpi_mainnet.json b/config/jsons/fpi_mainnet.json index c7a63d5..b0d645f 100644 --- a/config/jsons/fpi_mainnet.json +++ b/config/jsons/fpi_mainnet.json @@ -106,7 +106,10 @@ "symbol": "cUSYC", "decimals": 6, "underlying": "0xFb8255f0De21AcEBf490F1DF6F0BDd48CC1df03B", - "chainId": "7700" + "chainId": "7700", + "tags": [ + "hashnote" + ] }, { "name": "Collateral Treasury Bills", @@ -114,7 +117,10 @@ "symbol": "cfBill", "decimals": 18, "underlying": "0x79ecce8e2d17603877ff15bc29804cbcb590ec08", - "chainId": "7700" + "chainId": "7700", + "tags": [ + "fbill" + ] }, { "name": "Collateral International Treasury Bills", @@ -122,7 +128,10 @@ "symbol": "cifBill", "decimals": 18, "underlying": "0x45bafad5a6a531bc18cf6ce5b02c58ea4d20589b", - "chainId": "7700" + "chainId": "7700", + "tags": [ + "fbill" + ] } ], "tokens": [ diff --git a/config/tokens.go b/config/tokens.go index 0ca92e8..581b265 100644 --- a/config/tokens.go +++ b/config/tokens.go @@ -38,13 +38,14 @@ type Underlying struct { } type Token struct { - Name string `json:"name"` - Address string `json:"address"` - Symbol string `json:"symbol"` - Decimals int64 `json:"decimals"` - Underlying string `json:"underlying,omitempty"` - ChainID string `json:"chainId"` - LogoURI string `json:"logoURI,omitempty"` + Name string `json:"name"` + Address string `json:"address"` + Symbol string `json:"symbol"` + Decimals int64 `json:"decimals"` + Underlying string `json:"underlying,omitempty"` + ChainID string `json:"chainId"` + LogoURI string `json:"logoURI,omitempty"` + Tags []string `json:"tags,omitempty"` } type Pair struct { @@ -180,13 +181,17 @@ func GetLpPairData(address string) (symbol string, decimals int64, token1 Token, } // get ctoken data (Symbol, Name, Decimals, Underlying) from tokens config using cToken address -func GetCTokenData(address string) (symbol string, name string, decimals int64, underlying Underlying) { +func GetCTokenData(address string) (symbol string, name string, decimals int64, tags []string, underlying Underlying) { for _, cToken := range FPIConfig.CTokens { if cToken.Address == address { symbol = cToken.Symbol name = cToken.Name decimals = cToken.Decimals underlying = GetUnderlyingData(cToken.Underlying) + tags = []string{} + if cToken.Tags != nil { + tags = cToken.Tags + } return } } diff --git a/queryengine/contracts/utils.go b/queryengine/contracts/utils.go index 27ae40f..1095c67 100644 --- a/queryengine/contracts/utils.go +++ b/queryengine/contracts/utils.go @@ -6,6 +6,7 @@ import ( "fmt" "math" "math/big" + "time" "canto-api/config" "canto-api/multicall" @@ -115,6 +116,43 @@ func GetLpPairRatio(reserve1 *big.Int, reserve2 *big.Int) (*big.Int, bool) { } } +// convert big.Int to big.float +func BigIntToFloat64(value *big.Int) *big.Float { + return new(big.Float).SetInt(value) +} + +// holiday mapping for day to days interest update +var holidayMap = map[string]float64{ + "30" + time.December.String(): 4, + "13" + time.January.String(): 4, + "17" + time.February.String(): 4, + "25" + time.May.String(): 4, +} + +// get amount of days passed for hashnote interest update (includes holidy schedule) +func GetInterestDaysPassed(updatedAt int64) float64 { + // get time from UNIX timestamp + unixTime := time.Unix(updatedAt, 0) + // check for holidays + daysOffset := holidayMap[fmt.Sprintf("%d%s", unixTime.Day(), unixTime.Month().String())] + if daysOffset != 0 { + return daysOffset + } + // check if saturday reporting (for three days) + if unixTime.Weekday() == time.Saturday { + return 3 + } + return 1 +} + +// get hashnote apy +func HashnoteAPY(balance *big.Int, interest *big.Int, updatedAt *big.Int) float64 { + prevBalance := new(big.Float).Sub(BigIntToFloat64(balance), BigIntToFloat64(interest)) + spotAPY, _ := new(big.Float).Quo(BigIntToFloat64(interest), prevBalance).Float64() + dayOffset := GetInterestDaysPassed(updatedAt.Int64()) + return (spotAPY * 365 * 100) / dayOffset +} + // APY takes the block rate, calculates APY and returns func APY(blockRate *big.Int) float64 { // format blockRate by 1e18 @@ -203,7 +241,7 @@ func GetProcessedCTokens(ctx context.Context, cTokens TokensMap) ([]ProcessedCTo // key is address of cToken and value is a map of cToken data for address, cToken := range cTokens { // get cToken data - symbol, name, decimals, underlying := config.GetCTokenData(address) + symbol, name, decimals, tags, underlying := config.GetCTokenData(address) // process data cash, _ := InterfaceToBigInt(cToken["cash"][0]) @@ -228,6 +266,20 @@ func GetProcessedCTokens(ctx context.Context, cTokens TokensMap) ([]ProcessedCTo supplyBlockRate, _ := InterfaceToBigInt(cToken["supplyRatePerBlock"][0]) supplyApy := APY(supplyBlockRate) + // check tags that may affect this supply rate number + for _, tag := range tags { + if tag == "hashnote" { + // use latest round details to calculate supplyApy + balance, _ := InterfaceToBigInt(cToken["latestRoundDetails"][1]) + interest, _ := InterfaceToBigInt(cToken["latestRoundDetails"][2]) + updatedAt, _ := InterfaceToBigInt(cToken["latestRoundDetails"][4]) + supplyApy = HashnoteAPY(balance, interest, updatedAt) + } + if tag == "fbill" { + supplyApy = 4.90 + } + } + // get borrowApy using APY() borrowBlockRate, _ := InterfaceToBigInt(cToken["borrowRatePerBlock"][0]) borrowApy := APY(borrowBlockRate) @@ -253,22 +305,22 @@ func GetProcessedCTokens(ctx context.Context, cTokens TokensMap) ([]ProcessedCTo underlyingTotalSupply, _ := InterfaceToString(cToken["underlyingSupply"][0]) processedCToken := ProcessedCToken{ - Address: address, - Symbol: symbol, - Name: name, - Decimals: decimals, - Underlying: underlying, - Cash: cash.String(), - ExchangeRate: exchangeRate, - IsListed: isListed, - CollateralFactor: collateralFactor, - Price: price.String(), - BorrowCap: borrowCap.String(), - Liquidity: fmt.Sprintf("%.2f", liquidity), - SupplyApy: fmt.Sprintf("%.2f", supplyApy), - BorrowApy: fmt.Sprintf("%.2f", borrowApy), - DistApy: fmt.Sprintf("%.2f", distApy), - CompSupplyState: compSupplyState, + Address: address, + Symbol: symbol, + Name: name, + Decimals: decimals, + Underlying: underlying, + Cash: cash.String(), + ExchangeRate: exchangeRate, + IsListed: isListed, + CollateralFactor: collateralFactor, + Price: price.String(), + BorrowCap: borrowCap.String(), + Liquidity: fmt.Sprintf("%.2f", liquidity), + SupplyApy: fmt.Sprintf("%.2f", supplyApy), + BorrowApy: fmt.Sprintf("%.2f", borrowApy), + DistApy: fmt.Sprintf("%.2f", distApy), + CompSupplyState: compSupplyState, UnderlyingTotalSupply: underlyingTotalSupply, }