浏览代码

Refactoring and finished up fund submission

master
Jared 1年前
父节点
当前提交
3ed9898c92
共有 10 个文件被更改,包括 183 次插入119 次删除
  1. +5
    -0
      client/client.go
  2. +2
    -0
      data/context.go
  3. +1
    -2
      endpoints/analytics.go
  4. +5
    -6
      endpoints/contribute.go
  5. +7
    -3
      endpoints/contributionstream.go
  6. +2
    -54
      endpoints/createrewardfund.go
  7. +2
    -1
      endpoints/getbalance.go
  8. +98
    -53
      endpoints/submitfund.go
  9. +1
    -0
      main.go
  10. +60
    -0
      utils/offers.go

+ 5
- 0
client/client.go 查看文件

@@ -0,0 +1,5 @@
package client

import "github.com/stellar/go/clients/horizonclient"

var SignetClient = horizonclient.DefaultTestNetClient

+ 2
- 0
data/context.go 查看文件

@@ -34,6 +34,7 @@ type RewardFund struct {
ModelBase
Asset string `json:"asset"`
FundWallet string `json:"fundWallet"`
FundSecret string `json:"fundSecret"`
SellingWallet string `json:"sellingWallet"`
IssuerWallet string `json:"issuerWallet"`
Memo string `json:"memo"`
@@ -57,6 +58,7 @@ type Contribution struct {
ModelBase
Wallet string `json:"wallet"`
Amount float64 `gorm:"type:decimal(19,7)" json:"amount"`
Submitted bool `gorm:"type:boolean" json:"submitted"`
TransactionID string `json:"transactionID"`
RewardFundID uint `json:"rewardFundID"`
}


+ 1
- 2
endpoints/analytics.go 查看文件

@@ -38,8 +38,7 @@ func NearlyCompleteFunds(w http.ResponseWriter, r *http.Request) {
Db.Table("contributions").
Select("rf.id", "asset", "min_contribution", "amount_available", "memo", "fund_wallet", "sum(amount) as raised").
Joins("inner join reward_funds rf on rf.id = contributions.reward_fund_id").
Group("asset, rf.id, min_contribution, amount_available, memo, fund_wallet").
Having("sum(amount) between (rf.amount_available * ?) and rf.amount_available", req.Threshold/100).
Where("rf.amount_available < ?", req.Threshold).
Scan(&resp.Funds)
err = json.NewEncoder(w).Encode(resp)
if err != nil {


+ 5
- 6
endpoints/contribute.go 查看文件

@@ -6,6 +6,7 @@ import (
"net/http"
"strings"

"github.com/imosed/signet/client"
. "github.com/imosed/signet/data"
"github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient"
@@ -44,9 +45,9 @@ func Contribute(resp http.ResponseWriter, req *http.Request) {
source := keypair.MustParseFull(cont.PrivateKey)
sourceReq := horizonclient.AccountRequest{AccountID: source.Address()}
var sourceAcct horizon.Account
sourceAcct, err = client.AccountDetail(sourceReq)
sourceAcct, err = client.SignetClient.AccountDetail(sourceReq)
if err != nil {
log.Error().Err(err).Msg("Could not get account details from Horizon client")
log.Error().Err(err).Msg("Could not get account details from Horizon SignetClient")
return
}

@@ -80,15 +81,13 @@ func Contribute(resp http.ResponseWriter, req *http.Request) {
}

var response horizon.Transaction
response, err = client.SubmitTransaction(tx)
response, err = client.SignetClient.SubmitTransaction(tx)
if err != nil {
log.Error().Err(err).Msg("Could not submit contribution transaction")
return
}

fmt.Println("Successful Transaction:")
fmt.Println("Ledger:", response.Ledger)
fmt.Println("Hash:", response.Hash)
log.Info().Msg(fmt.Sprintf("Successful Transaction: { Ledger: %d, Hash: %s }", response.Ledger, response.Hash))

var result SuccessResponse
result.Success = response.Successful && err == nil


+ 7
- 3
endpoints/contributionstream.go 查看文件

@@ -6,6 +6,7 @@ import (
"strings"

"github.com/gorilla/websocket"
"github.com/imosed/signet/client"
. "github.com/imosed/signet/data"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
@@ -52,13 +53,16 @@ func InitializeContributionStreams() {
Db.Table("reward_funds").Select("fund_wallet").Scan(&wallets)

contributionUpdateHandler := func(op operations.Operation) {
if op.GetBase().GetTypeI() == 6 || op.GetBase().GetTypeI() == 12 {
return
}
payment := op.(operations.Payment)

var tx horizon.Transaction
var amt float64
var fund RewardFund

tx, err = client.TransactionDetail(payment.GetTransactionHash())
tx, err = client.SignetClient.TransactionDetail(payment.GetTransactionHash())
if err != nil {
log.Error().Err(err).Msg("Could not get transaction from hash")
return
@@ -104,9 +108,9 @@ func InitializeContributionStreams() {
opReq.SetOperationsEndpoint()
ctx, cancellation := context.WithCancel(context.Background())
cancellations = append(cancellations, cancellation)
err = client.StreamOperations(ctx, opReq, contributionUpdateHandler)
err = client.SignetClient.StreamOperations(ctx, opReq, contributionUpdateHandler)
if err != nil {
log.Error().Err(err).Msg("Failed to stream contributions from Horizon client")
log.Error().Err(err).Msg("Failed to stream contributions from Horizon SignetClient")
}
}
}

+ 2
- 54
endpoints/createrewardfund.go 查看文件

@@ -2,16 +2,14 @@ package endpoints

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"

"github.com/imosed/signet/auth"
. "github.com/imosed/signet/data"
"github.com/imosed/signet/utils"
"github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/protocols/horizon"
)

type CreateRewardFundRequest struct {
@@ -66,7 +64,7 @@ func CreateRewardFund(resp http.ResponseWriter, req *http.Request) {
Order: horizonclient.OrderDesc,
}

if err, ok := FindOffer(offerReq, &rewardFund); !ok {
if err, ok := utils.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")
@@ -108,53 +106,3 @@ func CreateRewardFund(resp http.ResponseWriter, req *http.Request) {
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
}
}

+ 2
- 1
endpoints/getbalance.go 查看文件

@@ -5,6 +5,7 @@ import (
"net/http"
"strconv"

"github.com/imosed/signet/client"
"github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/keypair"
@@ -38,7 +39,7 @@ func GetBalance(w http.ResponseWriter, r *http.Request) {
AccountID: kp.Address(),
}
var acct horizon.Account
acct, err = client.AccountDetail(acctReq)
acct, err = client.SignetClient.AccountDetail(acctReq)
if err != nil {
log.Error().Err(err).Msg("Could not get account data from public key")
return


+ 98
- 53
endpoints/submitfund.go 查看文件

@@ -5,16 +5,22 @@ import (
"fmt"
"net/http"

"github.com/imosed/signet/client"
. "github.com/imosed/signet/data"
"github.com/imosed/signet/utils"
"github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/keypair"
"github.com/stellar/go/network"
"github.com/stellar/go/protocols/horizon"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"
"gorm.io/gorm/clause"
)

var client = horizonclient.DefaultTestNetClient

type SubmitFundRequest struct {
FundID uint `json:"fundId"`
FundID uint `json:"fundID"`
Submit bool `json:"submit"`
}

func SubmitFund(w http.ResponseWriter, r *http.Request) {
@@ -25,69 +31,108 @@ func SubmitFund(w http.ResponseWriter, r *http.Request) {
}

var fund RewardFund
Db.Find(&fund, req.FundID)
Db.Preload(clause.Associations).Find(&fund, req.FundID)

// source := keypair.MustParseFull(fund.FundWallet)
// sourceReq := horizonclient.AccountRequest{AccountID: source.Address()}
// var sourceAcct horizon.Account
// sourceAcct, err = client.AccountDetail(sourceReq)
var resp SuccessResponse
if !req.Submit {
json.NewEncoder(w).Encode(&SuccessResponse{Success: false})
return
}

source := keypair.MustParseFull(fund.FundSecret)
sourceReq := horizonclient.AccountRequest{AccountID: source.Address()}
var sourceAcct horizon.Account
sourceAcct, err = client.SignetClient.AccountDetail(sourceReq)

offerReq := horizonclient.OfferRequest{
Seller: fund.SellingWallet,
Selling: fmt.Sprintf("%s:%s", fund.Asset, fund.IssuerWallet),
Seller: fund.IssuerWallet,
Cursor: "0",
Order: horizonclient.OrderDesc,
}

var offers horizon.OffersPage
offers, err = client.Offers(offerReq)
for _, o := range offers.Embedded.Records {
if float64(o.PriceR.N)/float64(o.PriceR.D) == fund.Price {
fmt.Println(o.PriceR.N)
fmt.Println(o.Amount)
if err, ok := utils.FindOffer(offerReq, &fund); !ok {
err = json.NewEncoder(w).Encode(&SuccessResponse{Success: ok})
if err != nil {
log.Error().Err(err).Msg("Could not deliver response after failing to find issuer offer in submission")
}
return
}

// var tx *txnbuild.Transaction
// tx, err = txnbuild.NewTransaction(
// txnbuild.TransactionParams{
// SourceAccount: &sourceAcct,
// IncrementSequenceNum: true,
// Operations: []txnbuild.Operation{
// &txnbuild.ManageBuyOffer{
// Selling: txnbuild.NativeAsset{},
// Buying: txnbuild.CreditAsset{
// Code: fund.Asset,
// Issuer: fund.IssuerWallet,
// },
// Amount: fmt.Sprintf("%f", SumContributions(fund.Contributions)),
// Price: xdr.Price{}, // TODO: get price
// OfferID: 0,
// SourceAccount: "",
// },
// },
// BaseFee: txnbuild.MinBaseFee,
// Memo: txnbuild.Memo(txnbuild.MemoText(strconv.Itoa(int(fund.Model.ID)))),
// Preconditions: txnbuild.Preconditions{
// TimeBounds: txnbuild.NewInfiniteTimeout(), // TODO: change from infinite
// },
// })
// if err != nil {
// log.Error().Err(err).Msg("Could not submit reward fund")
// }
//
// tx, err = tx.Sign(network.TestNetworkPassphrase, source)
// if err != nil {
// log.Error().Err(err).Msg("Could not submit fund")
// }
//
// var response horizon.Transaction
// response, err = client.SubmitTransaction(tx)
var currentContributions = fund.Contributions
var submissionAmount = SumContributions(currentContributions)

var resp SuccessResponse
// resp.Success = response.Successful
tr := Db.Begin()
tr.Table("contributions").
Where("reward_fund_id = ? and submitted is null or submitted = false", req.FundID).
Updates(Contribution{Submitted: true})

var tx *txnbuild.Transaction
tx, err = txnbuild.NewTransaction(
txnbuild.TransactionParams{
SourceAccount: &sourceAcct,
IncrementSequenceNum: true,
Operations: []txnbuild.Operation{
&txnbuild.ChangeTrust{
Line: txnbuild.CreditAsset{
Code: fund.Asset,
Issuer: fund.IssuerWallet,
}.MustToChangeTrustAsset(),
SourceAccount: fund.FundWallet,
},
&txnbuild.ManageBuyOffer{
Selling: txnbuild.NativeAsset{},
Buying: txnbuild.CreditAsset{
Code: fund.Asset,
Issuer: fund.IssuerWallet,
},
Amount: fmt.Sprintf("%f", submissionAmount),
Price: xdr.Price{N: 1, D: xdr.Int32(fund.Price)},
OfferID: 0,
SourceAccount: fund.FundWallet,
},
},
BaseFee: txnbuild.MinBaseFee,
Memo: txnbuild.Memo(nil),
Preconditions: txnbuild.Preconditions{
TimeBounds: txnbuild.NewInfiniteTimeout(), // TODO: change from infinite
},
})
if err != nil {
log.Error().Err(err).Msg("Could not build submission transaction")
tr.Rollback()
return
}

tx, err = tx.Sign(network.TestNetworkPassphrase, source)
if err != nil {
log.Error().Err(err).Msg("Could not sign submission transaction")
tr.Rollback()
return
}

var response horizon.Transaction
response, err = client.SignetClient.SubmitTransaction(tx)
if err != nil {
log.Error().Err(err).Msg("Could not submit transaction")
tr.Rollback()
return
}

tr.Commit()
resp.Success = response.Successful

err = json.NewEncoder(w).Encode(resp)
if err != nil {
log.Error().Err(err).Msg("Could not deliver response in SubmitFund call")
}
}

func SumContributions(contributions []Contribution) float64 {
var total float64 = 0
for _, contribution := range contributions {
if !contribution.Submitted {
total += contribution.Amount
}
}
return total
}

+ 1
- 0
main.go 查看文件

@@ -40,6 +40,7 @@ func main() {
router.HandleFunc("/EditQueue", endpoints.EditQueue)
router.HandleFunc("/CreateRewardFund", endpoints.CreateRewardFund)
router.HandleFunc("/CloseRewardFund", endpoints.CloseRewardFund)
router.HandleFunc("/SubmitRewardFund", endpoints.SubmitFund)
// router.HandleFunc("/SubmitFund", endpoints.SubmitFund)
router.HandleFunc("/GetBalance", endpoints.GetBalance)
router.HandleFunc("/Contribute", endpoints.Contribute)


+ 60
- 0
utils/offers.go 查看文件

@@ -0,0 +1,60 @@
package utils

import (
"errors"
"strconv"

"github.com/imosed/signet/client"
"github.com/imosed/signet/data"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/protocols/horizon"
)

func FindOffer(offerReq horizonclient.OfferRequest, rewardFund *data.RewardFund) (error, bool) {
op, err := client.SignetClient.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
}
amt, err = strconv.ParseFloat(correctOffer.Amount, 64)
if err != nil {
return errors.New("could not parse correct offer amount to float"), false
}
rewardFund.Price = price
rewardFund.AmountAvailable = amt
return nil, true
} else {
return nil, false // no offers shouldn't error
}
}

正在加载...
取消
保存