package endpoints import ( "encoding/json" "errors" "fmt" "net/http" "strconv" "github.com/imosed/signet/auth" . "github.com/imosed/signet/data" "github.com/rs/zerolog/log" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/protocols/horizon" ) type CreateRewardFundRequest struct { Asset string `json:"asset"` FundWallet string `json:"fundWallet"` SellingWallet string `json:"sellingWallet"` IssuerWallet string `json:"issuerWallet"` Memo string `json:"memo"` MinContribution float64 `gorm:"type:decimal(19,7)" json:"minContribution"` TelegramLink string `json:"telegramLink"` QueueID uint `json:"queueID"` Bonuses []Bonus `json:"bonuses"` } type SuccessResponse struct { Success bool `json:"success"` } func CreateRewardFund(resp http.ResponseWriter, req *http.Request) { var fund CreateRewardFundRequest dec := json.NewDecoder(req.Body) err := dec.Decode(&fund) if err != nil { log.Error().Err(err).Msg("Could not read submitted reward fund") return } var bonuses []Bonus rewardFund := RewardFund{ Asset: fund.Asset, FundWallet: fund.FundWallet, SellingWallet: fund.SellingWallet, IssuerWallet: fund.IssuerWallet, Memo: fund.Memo, Price: 0, AmountAvailable: 0, MinContribution: fund.MinContribution, TelegramLink: fund.TelegramLink, Contributions: nil, } var fundsInQueue []RewardFund Db.Table("queue_reward_funds").Where("queue_id = ?", fund.QueueID).Scan(&fundsInQueue) next := uint16(len(fundsInQueue)) joinRecord := QueueOrder{QueueID: fund.QueueID, RewardFundID: rewardFund.ID, Order: next} offerReq := horizonclient.OfferRequest{ Seller: rewardFund.SellingWallet, Selling: fmt.Sprintf("%s:%s", rewardFund.Asset, rewardFund.IssuerWallet), Order: horizonclient.OrderDesc, } if err, ok := FindOffer(offerReq, &rewardFund); !ok { err = json.NewEncoder(resp).Encode(&SuccessResponse{Success: ok}) if err != nil { log.Error().Err(err).Msg("Could not deliver response after failing to find issuer offer") } return } if err != nil { log.Error().Err(err).Msg("Could not find issuer offer") return } var claims *auth.Claims claims, err = auth.GetUserClaims(req) if err != nil { log.Error().Err(err).Msg("Could not determine if user is authenticated") return } if claims.Privileges <= Admin { Db.Create(&rewardFund) Db.Create(&joinRecord) for _, cancel := range cancellations { cancel() } go InitializeContributionStreams() for _, bonus := range fund.Bonuses { bonus.RewardFundID = rewardFund.ID bonuses = append(bonuses, bonus) } Db.Create(&bonuses) err = json.NewEncoder(resp).Encode(&SuccessResponse{Success: true}) if err != nil { log.Error().Err(err).Msg("Could not create response for created reward fund") } } else { resp.WriteHeader(403) } } func FindOffer(offerReq horizonclient.OfferRequest, rewardFund *RewardFund) (error, bool) { op, err := client.Offers(offerReq) if err != nil { return errors.New("could not get offers"), false } offers := op.Embedded.Records var price float64 var amt float64 if len(offers) == 1 { price, err = strconv.ParseFloat(op.Embedded.Records[0].Price, 64) if err != nil { return errors.New("could not parse single offer price to float"), false } amt, err = strconv.ParseFloat(op.Embedded.Records[0].Amount, 64) if err != nil { return errors.New("could not parse single offer amount to float"), false } rewardFund.Price = price rewardFund.AmountAvailable = amt return nil, true } else if len(offers) > 1 { var maxOffers float64 = 0 var correctOffer horizon.Offer for _, o := range op.Embedded.Records { parsedAmt, err := strconv.ParseFloat(o.Amount, 64) if err != nil { return errors.New("could not parse amount from offer slice to float"), false } if parsedAmt > maxOffers { correctOffer = o maxOffers = parsedAmt } } price, err = strconv.ParseFloat(correctOffer.Price, 64) if err != nil { return errors.New("could not parse correct offer price to float"), false } rewardFund.Price = price amt, err = strconv.ParseFloat(correctOffer.Amount, 64) if err != nil { return errors.New("could not parse correct offer amount to float"), false } rewardFund.AmountAvailable = amt return nil, true } else { return nil, false // no offers shouldn't error } }