diff --git a/engine/portfolio.go b/engine/portfolio.go index 81363547..3e239b12 100644 --- a/engine/portfolio.go +++ b/engine/portfolio.go @@ -60,11 +60,11 @@ func (p *portfolioManager) run() { log.Debugf(log.PortfolioMgr, "Portfolio manager shutdown.") }() + p.processPortfolio() for { select { case <-p.shutdown: return - case <-tick.C: p.processPortfolio() } diff --git a/portfolio/portfolio.go b/portfolio/portfolio.go index bb79d800..33f85fc4 100644 --- a/portfolio/portfolio.go +++ b/portfolio/portfolio.go @@ -13,6 +13,7 @@ import ( const ( cryptoIDAPIURL = "https://chainz.cryptoid.info" + xrpScanAPIURL = "https://api.xrpscan.com/api/v1/account/" ethplorerAPIURL = "https://api.ethplorer.io" ethplorerAddressInfo = "getAddressInfo" @@ -66,6 +67,16 @@ func GetCryptoIDAddress(address string, coinType currency.Code) (float64, error) return result.(float64), nil } +// GetRippleBalance returns the value for a ripple address +func GetRippleBalance(address string) (float64, error) { + var result XRPScanAccount + err := common.SendHTTPGetRequest(xrpScanAPIURL+address, true, Verbose, &result) + if err != nil { + return 0, err + } + return result.XRPBalance, nil +} + // GetAddressBalance acceses the portfolio base and returns the balance by passed // in address, coin type and description func (p *Base) GetAddressBalance(address, description string, coinType currency.Code) (float64, bool) { @@ -210,7 +221,8 @@ func (p *Base) UpdatePortfolio(addresses []string, coinType currency.Code) error return nil } - if coinType == currency.ETH { + switch coinType { + case currency.ETH: for x := range addresses { result, err := GetEthereumBalance(addresses[x]) if err != nil { @@ -221,21 +233,42 @@ func (p *Base) UpdatePortfolio(addresses []string, coinType currency.Code) error return errors.New(result.Error.Message) } - p.AddAddress(addresses[x], + err = p.AddAddress(addresses[x], PortfolioAddressPersonal, coinType, result.ETH.Balance) + if err != nil { + return err + } } - } - for x := range addresses { - result, err := GetCryptoIDAddress(addresses[x], coinType) - if err != nil { - return err + case currency.XRP: + for x := range addresses { + result, err := GetRippleBalance(addresses[x]) + if err != nil { + return err + } + err = p.AddAddress(addresses[x], + PortfolioAddressPersonal, + coinType, + result) + if err != nil { + return err + } + } + default: + for x := range addresses { + result, err := GetCryptoIDAddress(addresses[x], coinType) + if err != nil { + return err + } + err = p.AddAddress(addresses[x], + PortfolioAddressPersonal, + coinType, + result) + if err != nil { + return err + } } - p.AddAddress(addresses[x], - PortfolioAddressPersonal, - coinType, - result) } return nil } @@ -425,9 +458,10 @@ func StartPortfolioWatcher() { err := Portfolio.UpdatePortfolio(value, key) if err != nil { log.Errorf(log.PortfolioMgr, - "PortfolioWatcher error %s for currency %s\n", + "PortfolioWatcher error %s for currency %s, val %v\n", err, - key) + key, + value) continue } diff --git a/portfolio/portfolio_test.go b/portfolio/portfolio_test.go index e17ddd63..c2baac7a 100644 --- a/portfolio/portfolio_test.go +++ b/portfolio/portfolio_test.go @@ -74,6 +74,20 @@ func TestGetAddressBalance(t *testing.T) { } } +func TestGetRippleBalance(t *testing.T) { + nonsenseAddress := "Wigwham" + _, err := GetRippleBalance(nonsenseAddress) + if err == nil { + t.Error("error cannot be nil on a bad address") + } + + rippleAddress := "r962iS5subzbVeXZN8MTzyEuuaQKo5qksh" + _, err = GetRippleBalance(rippleAddress) + if err != nil { + t.Error(err) + } +} + func TestExchangeExists(t *testing.T) { newBase := Base{} newBase.AddAddress("someaddress", @@ -275,8 +289,9 @@ func TestUpdatePortfolio(t *testing.T) { if err == nil { t.Error("portfolio_test.go - UpdatePortfolio error cannot be nil") } - err = portfolio.UpdatePortfolio( - []string{"LdP8Qox1VAhCzLJNqrr74YovaWYyNBUWvL", "LVa8wZ983PvWtdwXZ8viK6SocMENLCXkEy"}, + err = portfolio.UpdatePortfolio([]string{ + "LdP8Qox1VAhCzLJNqrr74YovaWYyNBUWvL", + "LVa8wZ983PvWtdwXZ8viK6SocMENLCXkEy"}, currency.LTC, ) if err != nil { @@ -290,26 +305,42 @@ func TestUpdatePortfolio(t *testing.T) { } time.Sleep(time.Second * 5) - err = portfolio.UpdatePortfolio( - []string{"0xb794f5ea0ba39494ce839613fffba74279579268", - "0xe853c56864a2ebe4576a807d26fdc4a0ada51919"}, currency.ETH, - ) - if err == nil { // eth support seems to have been dropped for cryptoid - t.Error("portfolio_test.go - UpdatePortfolio error cannot be nil") + err = portfolio.UpdatePortfolio([]string{ + "0xb794f5ea0ba39494ce839613fffba74279579268", + "0xe853c56864a2ebe4576a807d26fdc4a0ada51919"}, + currency.ETH) + if err != nil { + t.Error(err) } - err = portfolio.UpdatePortfolio( - []string{"0xb794f5ea0ba39494ce839613fffba74279579268", "TESTY"}, currency.ETH, - ) + err = portfolio.UpdatePortfolio([]string{ + "0xb794f5ea0ba39494ce839613fffba74279579268", + "TESTY"}, + currency.ETH) if err == nil { t.Error("portfolio_test.go - UpdatePortfolio error cannot be nil") } - err = portfolio.UpdatePortfolio( - []string{PortfolioAddressExchange, PortfolioAddressPersonal}, currency.LTC) - + err = portfolio.UpdatePortfolio([]string{PortfolioAddressExchange, + PortfolioAddressPersonal}, + currency.LTC) if err != nil { t.Error("portfolio_test.go - UpdatePortfolio error", err) } + + err = portfolio.UpdatePortfolio([]string{ + "r962iS5subzbVeXZN8MTzyEuuaQKo5qksh"}, + currency.XRP) + if err != nil { + t.Error("portfolio_test.go - UpdatePortfolio error", err) + } + + err = portfolio.UpdatePortfolio([]string{ + "r962iS5subzbVeXZN8MTzyEuuaQKo5qksh", + "TESTY"}, + currency.XRP) + if err == nil { + t.Error("error cannot be nil") + } } func TestGetPortfolioByExchange(t *testing.T) { diff --git a/portfolio/portfolio_types.go b/portfolio/portfolio_types.go index 658039bc..63207751 100644 --- a/portfolio/portfolio_types.go +++ b/portfolio/portfolio_types.go @@ -1,6 +1,10 @@ package portfolio -import "github.com/thrasher-corp/gocryptotrader/currency" +import ( + "time" + + "github.com/thrasher-corp/gocryptotrader/currency" +) // Base holds the portfolio base addresses type Base struct { @@ -120,3 +124,39 @@ type Summary struct { Online []Coin `json:"coins_online"` OnlineSummary map[string]map[currency.Code]OnlineCoinSummary `json:"online_summary"` } + +// XRPScanAccount defines the return type for account data +type XRPScanAccount struct { + Sequence int `json:"sequence"` + XRPBalance float64 `json:"xrpBalance,string"` + OwnerCount int `json:"ownerCount"` + PreviousAffectingTransactionID string `json:"previousAffectingTransactionID"` + PreviousAffectingTransactionLedgerVersion int `json:"previousAffectingTransactionLedgerVersion"` + Settings struct { + RequireDestinationTag bool `json:"requireDestinationTag"` + EmailHash string `json:"emailHash"` + Domain string `json:"domain"` + } `json:"settings"` + Account string `json:"account"` + Parent string `json:"parent"` + InitialBalance float64 `json:"initial_balance"` + Inception time.Time `json:"inception"` + LedgerIndex int `json:"ledger_index"` + TxHash string `json:"tx_hash"` + AccountName struct { + Name string `json:"name"` + Account string `json:"account"` + Domain string `json:"domain"` + Twitter string `json:"twitter"` + Verified bool `json:"verified"` + } `json:"accountName"` + ParentName struct { + Name string `json:"name"` + Desc string `json:"desc"` + Account string `json:"account"` + Domain string `json:"domain"` + Twitter string `json:"twitter"` + Verified bool `json:"verified"` + } `json:"parentName"` + Advisory interface{} `json:"advisory"` +}