diff --git a/frontend b/frontend index e12907b..2e352c1 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit e12907bb3109f2cc05c8d978469671998b700954 +Subproject commit 2e352c1798cd90ef27737d8ca7e54b394773a9b2 diff --git a/go.sum b/go.sum index cc8f9cd..7c8678f 100644 --- a/go.sum +++ b/go.sum @@ -217,4 +217,4 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= \ No newline at end of file diff --git a/models/PasswordReset.go b/models/PasswordReset.go index 2e88ebe..346afa3 100644 --- a/models/PasswordReset.go +++ b/models/PasswordReset.go @@ -60,7 +60,7 @@ func PasswordReset(email string) (string, error) { %s`, templates.HtmlPasswordResetTemplateHead, tempPass, templates.HtmlPasswordResetTemplateTail) plainContent := fmt.Sprintf(templates.PlainPasswordResetTemplate, tempPass) - err = utils.SendEmail("noreply@dalalstreet.com", "Password Reset", email, plainContent, htmlContent) + err = utils.SendEmail("noreply@dalal.pragyan.org", "Password Reset", email, plainContent, htmlContent) if err != nil { l.Errorf("Error while sending password reset email to player %s", err) diff --git a/models/Registration.go b/models/Registration.go index 83b9941..9c3e5b8 100644 --- a/models/Registration.go +++ b/models/Registration.go @@ -91,7 +91,7 @@ func ResendVerificationEmail(email string) error { %s %s`, templates.HtmlEmailVerificationTemplateHead, verificationURL, templates.HtmlEmailVerificationTemplateTail) plainContent := fmt.Sprintf(templates.PlainEmailVerificationTemplate, verificationURL) - if err := utils.SendEmail("noreply@dalalstreet.com", "Account Verification", email, plainContent, htmlContent); err != nil { + if err := utils.SendEmail("noreply@dalal.pragyan.org", "Account Verification", email, plainContent, htmlContent); err != nil { l.Errorf("Error while sending verification email to player %s", err) return err } diff --git a/models/User.go b/models/User.go index 286a8bc..ab83514 100644 --- a/models/User.go +++ b/models/User.go @@ -113,7 +113,6 @@ func Login(email, password string) (User, error) { var l = logger.WithFields(logrus.Fields{ "method": "Login", "param_email": email, - "param_password": password, }) l.Infof("Attempting to login user") @@ -219,7 +218,6 @@ func RegisterUser(email, password, fullName, referralCode string) error { var l = logger.WithFields(logrus.Fields{ "method": "Register", "param_email": email, - "param_password": password, }) l.Debugf("Attempting to register user") @@ -293,7 +291,7 @@ func RegisterUser(email, password, fullName, referralCode string) error { %s %s`, templates.HtmlEmailVerificationTemplateHead, verificationURL, templates.HtmlEmailVerificationTemplateTail) plainContent := fmt.Sprintf(templates.PlainEmailVerificationTemplate, verificationURL) - err = utils.SendEmail("noreply@dalalstreet.com", "Account Verification", email, plainContent, htmlContent) + err = utils.SendEmail("noreply@dalal.pragyan.org", "Account Verification", email, plainContent, htmlContent) if err != nil { l.Errorf("Error while sending verification email to player %s", err) return err @@ -423,7 +421,6 @@ func postLoginToPragyan(email, password string) (pragyanUser, error) { var l = logger.WithFields(logrus.Fields{ "method": "postLoginToPragyan", "param_email": email, - "param_name": password, }) form := url.Values{ @@ -607,6 +604,18 @@ func (e NotEnoughStocksError) Error() string { return fmt.Sprintf("Not have enough stocks to place this order. Current maximum Ask size: %d stocks", e.currentAllowedQty) } +// NotEnoughActualWorth is generated when an Ask's StockQuantity is such that +// deducting those many stocks will mean that with the current stock worth +// multiplied by number of stocks being short sold is more than the cash in +// hand and stock worth of the user +type NotEnoughActualWorthError struct { + actualWorth int64 +} + +func (e NotEnoughActualWorthError) Error() string { + return fmt.Sprintf("Not have actual networh to place this order. Cash in hand plus stock worth should be atleast: %d", e.actualWorth) +} + // NotEnoughCashError is generated when a Bid's StockQuantity*Price is such that // deducting so much cash from the user will leave him with less than // MINIMUM_CASH_LIMIT @@ -964,22 +973,71 @@ func PlaceAskOrder(userId uint32, ask *Ask) (uint32, error) { } l.Debugf("Check2: Passed.") + + + + var shortSellMin = numStocksLeft*int64(ask.Price) + var stockWorth int64 = 0 + + db := getDB() + + sql := "Select stockId, sum(stockQuantity) as stockQuantity from Transactions where userId=? group by stockId" + rows, err := db.Raw(sql, userId).Rows() + if err != nil { + l.Error(err) + return 0, err + } + defer rows.Close() + + stocksOwned := make(map[uint32]int64) + for rows.Next() { + var stockId uint32 + var stockQty int64 + rows.Scan(&stockId, &stockQty) + + stocksOwned[stockId] = stockQty + } + + + // Find Stock worth of user + for id, number := range stocksOwned{ + allStocks.m[id].RLock() + stockWorth = stockWorth + int64(allStocks.m[id].stock.CurrentPrice)*number + allStocks.m[id].RUnlock() + } + + //Actual worth of user includes only + //Stock worth and cash + //Does not include reserved cash and stocks + var actualWorth = int64(user.Cash) + stockWorth + + l.Debugf("Check3: Current stocks: %d. Stocks after trade: %d. User Actual Worth(Cash in hand + Stock Worth) %d", numStocks, numStocksLeft, user.Total) + + //Check if networth of user is more than the number of stocks + //which are short sold + if numStocksLeft < 0 && -(actualWorth) > shortSellMin { + l.Debugf("Check3: Failed. Not enough actual worth to short sell.") + return 0, NotEnoughActualWorthError{-shortSellMin} + } + + l.Debugf("Check3: Passed.") + orderPrice := getOrderFeePrice(ask.Price, ask.StockId, ask.OrderType) orderFee := getOrderFee(ask.StockQuantity, orderPrice) cashLeft := int64(user.Cash) - int64(orderFee) - l.Debugf("Check3: User has %d cash currently. Will be left with %d cash after trade.", user.Cash, cashLeft) + l.Debugf("Check4: User has %d cash currently. Will be left with %d cash after trade.", user.Cash, cashLeft) if cashLeft < MINIMUM_CASH_LIMIT { - l.Debugf("Check3: Failed. Not enough cash.") + l.Debugf("Check4: Failed. Not enough cash.") return 0, NotEnoughCashError{} } - l.Debugf("Check3: Passed. Creating Ask.") + l.Debugf("Check4: Passed. Creating Ask.") oldCash := user.Cash - db := getDB() + db = getDB() tx := db.Begin() var errorHelper = func(format string, args ...interface{}) (uint32, error) { diff --git a/models/User_test.go b/models/User_test.go index eedcfb4..b8829f7 100644 --- a/models/User_test.go +++ b/models/User_test.go @@ -163,8 +163,8 @@ func Test_PlaceAskOrder(t *testing.T) { transactions := []*Transaction{ makeTrans(2, 1, FromExchangeTransaction, 0, 10, 200, 0, 2000), - makeTrans(2, 1, FromExchangeTransaction, 0, -10, 200, 0, 2000), - makeTrans(2, 1, FromExchangeTransaction, 0, -10, 200, 0, 2000), + makeTrans(2, 1, FromExchangeTransaction, 0, 10, 200, 0, 2000), + makeTrans(2, 1, FromExchangeTransaction, 0, 10, 200, 0, 2000), } testcases := []struct {