The backend for the project formerly known as signet, now known as beignet.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

createrewardfund.go 4.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package endpoints
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "strconv"
  8. "github.com/imosed/signet/auth"
  9. . "github.com/imosed/signet/data"
  10. "github.com/rs/zerolog/log"
  11. "github.com/stellar/go/clients/horizonclient"
  12. "github.com/stellar/go/protocols/horizon"
  13. )
  14. type CreateRewardFundRequest struct {
  15. Asset string `json:"asset"`
  16. FundWallet string `json:"fundWallet"`
  17. SellingWallet string `json:"sellingWallet"`
  18. IssuerWallet string `json:"issuerWallet"`
  19. Memo string `json:"memo"`
  20. MinContribution float64 `gorm:"type:decimal(19,7)" json:"minContribution"`
  21. TelegramLink string `json:"telegramLink"`
  22. QueueID uint `json:"queueID"`
  23. Bonuses []Bonus `json:"bonuses"`
  24. }
  25. type SuccessResponse struct {
  26. Success bool `json:"success"`
  27. }
  28. func CreateRewardFund(resp http.ResponseWriter, req *http.Request) {
  29. var fund CreateRewardFundRequest
  30. dec := json.NewDecoder(req.Body)
  31. err := dec.Decode(&fund)
  32. if err != nil {
  33. log.Error().Err(err).Msg("Could not read submitted reward fund")
  34. return
  35. }
  36. var bonuses []Bonus
  37. rewardFund := RewardFund{
  38. Asset: fund.Asset,
  39. FundWallet: fund.FundWallet,
  40. SellingWallet: fund.SellingWallet,
  41. IssuerWallet: fund.IssuerWallet,
  42. Memo: fund.Memo,
  43. Price: 0,
  44. AmountAvailable: 0,
  45. MinContribution: fund.MinContribution,
  46. TelegramLink: fund.TelegramLink,
  47. Contributions: nil,
  48. }
  49. var fundsInQueue []RewardFund
  50. Db.Table("queue_reward_funds").Where("queue_id = ?", fund.QueueID).Scan(&fundsInQueue)
  51. next := uint16(len(fundsInQueue))
  52. joinRecord := QueueOrder{QueueID: fund.QueueID, RewardFundID: rewardFund.ID, Order: next}
  53. offerReq := horizonclient.OfferRequest{
  54. Seller: rewardFund.SellingWallet,
  55. Selling: fmt.Sprintf("%s:%s", rewardFund.Asset, rewardFund.IssuerWallet),
  56. Order: horizonclient.OrderDesc,
  57. }
  58. if err, ok := FindOffer(offerReq, &rewardFund); !ok {
  59. err = json.NewEncoder(resp).Encode(&SuccessResponse{Success: ok})
  60. if err != nil {
  61. log.Error().Err(err).Msg("Could not deliver response after failing to find issuer offer")
  62. }
  63. return
  64. }
  65. if err != nil {
  66. log.Error().Err(err).Msg("Could not find issuer offer")
  67. return
  68. }
  69. var claims *auth.Claims
  70. claims, err = auth.GetUserClaims(req)
  71. if err != nil {
  72. log.Error().Err(err).Msg("Could not determine if user is authenticated")
  73. return
  74. }
  75. if claims.Privileges <= Admin {
  76. Db.Create(&rewardFund)
  77. Db.Create(&joinRecord)
  78. for _, cancel := range cancellations {
  79. cancel()
  80. }
  81. go InitializeContributionStreams()
  82. for _, bonus := range fund.Bonuses {
  83. bonus.RewardFundID = rewardFund.ID
  84. bonuses = append(bonuses, bonus)
  85. }
  86. Db.Create(&bonuses)
  87. err = json.NewEncoder(resp).Encode(&SuccessResponse{Success: true})
  88. if err != nil {
  89. log.Error().Err(err).Msg("Could not create response for created reward fund")
  90. }
  91. } else {
  92. resp.WriteHeader(403)
  93. }
  94. }
  95. func FindOffer(offerReq horizonclient.OfferRequest, rewardFund *RewardFund) (error, bool) {
  96. op, err := client.Offers(offerReq)
  97. if err != nil {
  98. return errors.New("could not get offers"), false
  99. }
  100. offers := op.Embedded.Records
  101. var price float64
  102. var amt float64
  103. if len(offers) == 1 {
  104. price, err = strconv.ParseFloat(op.Embedded.Records[0].Price, 64)
  105. if err != nil {
  106. return errors.New("could not parse single offer price to float"), false
  107. }
  108. amt, err = strconv.ParseFloat(op.Embedded.Records[0].Amount, 64)
  109. if err != nil {
  110. return errors.New("could not parse single offer amount to float"), false
  111. }
  112. rewardFund.Price = price
  113. rewardFund.AmountAvailable = amt
  114. return nil, true
  115. } else if len(offers) > 1 {
  116. var maxOffers float64 = 0
  117. var correctOffer horizon.Offer
  118. for _, o := range op.Embedded.Records {
  119. parsedAmt, err := strconv.ParseFloat(o.Amount, 64)
  120. if err != nil {
  121. return errors.New("could not parse amount from offer slice to float"), false
  122. }
  123. if parsedAmt > maxOffers {
  124. correctOffer = o
  125. maxOffers = parsedAmt
  126. }
  127. }
  128. price, err = strconv.ParseFloat(correctOffer.Price, 64)
  129. if err != nil {
  130. return errors.New("could not parse correct offer price to float"), false
  131. }
  132. rewardFund.Price = price
  133. amt, err = strconv.ParseFloat(correctOffer.Amount, 64)
  134. if err != nil {
  135. return errors.New("could not parse correct offer amount to float"), false
  136. }
  137. rewardFund.AmountAvailable = amt
  138. return nil, true
  139. } else {
  140. return nil, false // no offers shouldn't error
  141. }
  142. }