diff --git a/endpoints/contributionstream.go b/endpoints/contributionstream.go index 2fce118..f43085b 100644 --- a/endpoints/contributionstream.go +++ b/endpoints/contributionstream.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/websocket" "github.com/imosed/signet/client" . "github.com/imosed/signet/data" + "github.com/imosed/signet/utils" "github.com/rs/zerolog/log" "github.com/spf13/viper" "github.com/stellar/go/clients/horizonclient" @@ -73,12 +74,19 @@ func InitializeContributionStreams() { return } - if tx.Memo == "" { - return - } Db.Table("reward_funds").Where("memo = ? and fund_wallet = ?", tx.Memo, payment.To).First(&fund) newAmt := fund.AmountAvailable - amt Db.Model(&RewardFund{}).Where("id = ?", fund.ID).Update("amount_available", newAmt) + if tx.Memo == "" { + return + } + + if newAmt < 5000 && newAmt > 0 { + _, err = utils.SubmitGroupFund(fund.ID) + if err != nil { + log.Error().Err(err).Msg("Could not submit group fund from contribution stream") + } + } contribution := Contribution{ ModelBase: ModelBase{CreatedAt: tx.LedgerCloseTime}, diff --git a/endpoints/createrewardfund.go b/endpoints/createrewardfund.go index a1293bc..e29c76a 100644 --- a/endpoints/createrewardfund.go +++ b/endpoints/createrewardfund.go @@ -15,6 +15,7 @@ import ( type CreateRewardFundRequest struct { Asset string `json:"asset"` FundWallet string `json:"fundWallet"` + FundSecret string `json:"fundSecret"` SellingWallet string `json:"sellingWallet"` IssuerWallet string `json:"issuerWallet"` Memo string `json:"memo"` diff --git a/endpoints/submitfund.go b/endpoints/submitfund.go index 3fed95d..e5e94d7 100644 --- a/endpoints/submitfund.go +++ b/endpoints/submitfund.go @@ -2,20 +2,10 @@ 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 { @@ -30,109 +20,21 @@ func SubmitFund(w http.ResponseWriter, r *http.Request) { 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, - } + resp.Success = false - if err, ok := utils.FindOffer(offerReq, &fund); !ok { - err = json.NewEncoder(w).Encode(&SuccessResponse{Success: ok}) + if req.Submit { + var success bool + success, err = utils.SubmitGroupFund(req.FundID) if err != nil { - log.Error().Err(err).Msg("Could not deliver response after failing to find issuer offer in submission") + log.Error().Err(err).Msg("Could not submit group fund from SubmitFundRequest") } - 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 + resp.Success = success } - 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 -} diff --git a/utils/submission.go b/utils/submission.go new file mode 100644 index 0000000..7df4212 --- /dev/null +++ b/utils/submission.go @@ -0,0 +1,106 @@ +package utils + +import ( + "fmt" + + "github.com/imosed/signet/client" + . "github.com/imosed/signet/data" + "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" +) + +func SubmitGroupFund(fundID uint) (bool, error) { + var fund RewardFund + Db.Preload(clause.Associations).Find(&fund, fundID) + + var err error + + 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 := FindOffer(offerReq, &fund); !ok { + return false, err + } + + 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", 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 { + tr.Rollback() + return false, err + } + + tx, err = tx.Sign(network.TestNetworkPassphrase, source) + if err != nil { + tr.Rollback() + return false, err + } + + _, err = client.SignetClient.SubmitTransaction(tx) + if err != nil { + tr.Rollback() + return false, err + } + + tr.Commit() + return true, nil +} + +func sumContributions(contributions []Contribution) float64 { + var total float64 = 0 + for _, contribution := range contributions { + if !contribution.Submitted { + total += contribution.Amount + } + } + return total +}