package endpoints import ( "encoding/json" "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" ) type SubmitFundRequest struct { FundID uint `json:"fundID"` Submit bool `json:"submit"` } func SubmitFund(w http.ResponseWriter, r *http.Request) { var req SubmitFundRequest err := json.NewDecoder(r.Body).Decode(&req) if err != nil { log.Error().Err(err).Msg("Could not decode body in SubmitFund call") } var fund RewardFund Db.Preload(clause.Associations).Find(&fund, req.FundID) 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), Order: horizonclient.OrderDesc, } 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 currentContributions = fund.Contributions var submissionAmount = SumContributions(currentContributions) 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 }