Browse Source

Refactoring and finished up fund submission

master
Jared 1 year ago
parent
commit
3ed9898c92
10 changed files with 183 additions and 119 deletions
  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 View File

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

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

var SignetClient = horizonclient.DefaultTestNetClient

+ 2
- 0
data/context.go View File

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


+ 1
- 2
endpoints/analytics.go View File

@@ -38,8 +38,7 @@ func NearlyCompleteFunds(w http.ResponseWriter, r *http.Request) {
Db.Table("contributions"). Db.Table("contributions").
Select("rf.id", "asset", "min_contribution", "amount_available", "memo", "fund_wallet", "sum(amount) as raised"). 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"). 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) Scan(&resp.Funds)
err = json.NewEncoder(w).Encode(resp) err = json.NewEncoder(w).Encode(resp)
if err != nil { if err != nil {


+ 5
- 6
endpoints/contribute.go View File

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


"github.com/imosed/signet/client"
. "github.com/imosed/signet/data" . "github.com/imosed/signet/data"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/clients/horizonclient"
@@ -44,9 +45,9 @@ func Contribute(resp http.ResponseWriter, req *http.Request) {
source := keypair.MustParseFull(cont.PrivateKey) source := keypair.MustParseFull(cont.PrivateKey)
sourceReq := horizonclient.AccountRequest{AccountID: source.Address()} sourceReq := horizonclient.AccountRequest{AccountID: source.Address()}
var sourceAcct horizon.Account var sourceAcct horizon.Account
sourceAcct, err = client.AccountDetail(sourceReq)
sourceAcct, err = client.SignetClient.AccountDetail(sourceReq)
if err != nil { 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 return
} }


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


var response horizon.Transaction var response horizon.Transaction
response, err = client.SubmitTransaction(tx)
response, err = client.SignetClient.SubmitTransaction(tx)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Could not submit contribution transaction") log.Error().Err(err).Msg("Could not submit contribution transaction")
return 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 var result SuccessResponse
result.Success = response.Successful && err == nil result.Success = response.Successful && err == nil


+ 7
- 3
endpoints/contributionstream.go View File

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


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


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


var tx horizon.Transaction var tx horizon.Transaction
var amt float64 var amt float64
var fund RewardFund var fund RewardFund


tx, err = client.TransactionDetail(payment.GetTransactionHash())
tx, err = client.SignetClient.TransactionDetail(payment.GetTransactionHash())
if err != nil { if err != nil {
log.Error().Err(err).Msg("Could not get transaction from hash") log.Error().Err(err).Msg("Could not get transaction from hash")
return return
@@ -104,9 +108,9 @@ func InitializeContributionStreams() {
opReq.SetOperationsEndpoint() opReq.SetOperationsEndpoint()
ctx, cancellation := context.WithCancel(context.Background()) ctx, cancellation := context.WithCancel(context.Background())
cancellations = append(cancellations, cancellation) cancellations = append(cancellations, cancellation)
err = client.StreamOperations(ctx, opReq, contributionUpdateHandler)
err = client.SignetClient.StreamOperations(ctx, opReq, contributionUpdateHandler)
if err != nil { 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 View File

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


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


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


type CreateRewardFundRequest struct { type CreateRewardFundRequest struct {
@@ -66,7 +64,7 @@ func CreateRewardFund(resp http.ResponseWriter, req *http.Request) {
Order: horizonclient.OrderDesc, 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}) err = json.NewEncoder(resp).Encode(&SuccessResponse{Success: ok})
if err != nil { if err != nil {
log.Error().Err(err).Msg("Could not deliver response after failing to find issuer offer") 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) 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 View File

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


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


+ 98
- 53
endpoints/submitfund.go View File

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


"github.com/imosed/signet/client"
. "github.com/imosed/signet/data" . "github.com/imosed/signet/data"
"github.com/imosed/signet/utils"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/stellar/go/clients/horizonclient" "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/protocols/horizon"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"
"gorm.io/gorm/clause"
) )


var client = horizonclient.DefaultTestNetClient

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


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


var fund RewardFund 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{ offerReq := horizonclient.OfferRequest{
Seller: fund.SellingWallet,
Selling: fmt.Sprintf("%s:%s", fund.Asset, fund.IssuerWallet), 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) err = json.NewEncoder(w).Encode(resp)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Could not deliver response in SubmitFund call") 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 View File

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


+ 60
- 0
utils/offers.go View File

@@ -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
}
}

Loading…
Cancel
Save