From fce073f1f3859ebbb78f8b71c81eb193de1c5ad2 Mon Sep 17 00:00:00 2001 From: oliha Date: Thu, 25 Jul 2019 16:12:29 -0400 Subject: [PATCH 01/15] use txnbuild --- api/exchange.go | 6 +- api/strategy.go | 10 ++-- cmd/trade.go | 5 +- gui/backend/autogenerate_bot.go | 61 ++++++++++++------- gui/backend/upsert_bot_config.go | 49 +++++++++++----- plugins/batchedExchange.go | 66 +++++++++++---------- plugins/composeStrategy.go | 8 +-- plugins/deleteSideStrategy.go | 10 ++-- plugins/makerModeFilter.go | 48 ++++++++------- plugins/mirrorStrategy.go | 34 +++++------ plugins/orderConstraintsFilter.go | 54 +++++++++-------- plugins/priceFeed.go | 5 +- plugins/sdex.go | 98 +++++++++++++++---------------- plugins/sdexFeed.go | 6 +- plugins/sellSideStrategy.go | 34 +++++------ plugins/submitFilter.go | 6 +- support/utils/functions.go | 69 ++++++++++++---------- terminator/terminator.go | 42 +++++++++---- trader/trader.go | 6 +- 19 files changed, 351 insertions(+), 266 deletions(-) diff --git a/api/exchange.go b/api/exchange.go index 38acaf9b8..57cb2d9e5 100644 --- a/api/exchange.go +++ b/api/exchange.go @@ -3,8 +3,8 @@ package api import ( "fmt" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/model" ) @@ -222,8 +222,8 @@ type Balance struct { // ExchangeShim is the interface we use as a generic API for all crypto exchanges type ExchangeShim interface { - SubmitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error - SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error // forced synchronous version of SubmitOps + SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error + SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error // forced synchronous version of SubmitOps GetBalanceHack(asset hProtocol.Asset) (*Balance, error) LoadOffersHack() ([]hProtocol.Offer, error) Constrainable diff --git a/api/strategy.go b/api/strategy.go index 7a0de795f..226fc46fe 100644 --- a/api/strategy.go +++ b/api/strategy.go @@ -1,25 +1,25 @@ package api import ( - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/model" ) // Strategy represents some logic for a bot to follow while doing market making type Strategy interface { - PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) + PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) PreUpdate(maxAssetA float64, maxAssetB float64, trustA float64, trustB float64) error - UpdateWithOps(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, error) + UpdateWithOps(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, error) PostUpdate() error GetFillHandlers() ([]FillHandler, error) } // SideStrategy represents a strategy on a single side of the orderbook type SideStrategy interface { - PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) + PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) PreUpdate(maxAssetA float64, maxAssetB float64, trustA float64, trustB float64) error - UpdateWithOps(offers []hProtocol.Offer) (ops []build.TransactionMutator, newTopOffer *model.Number, e error) + UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) PostUpdate() error GetFillHandlers() ([]FillHandler, error) } diff --git a/cmd/trade.go b/cmd/trade.go index 0ab95fe16..9d2f69f2b 100644 --- a/cmd/trade.go +++ b/cmd/trade.go @@ -12,7 +12,6 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" "github.com/spf13/cobra" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/config" @@ -196,7 +195,7 @@ func makeExchangeShimSdex( options inputs, client *horizonclient.Client, ieif *plugins.IEIF, - network build.Network, + network string, threadTracker *multithreading.ThreadTracker, tradingPair *model.TradingPair, ) (api.ExchangeShim, *plugins.SDEX) { @@ -288,7 +287,7 @@ func makeExchangeShimSdex( func makeStrategy( l logger.Logger, - network build.Network, + network string, botConfig trader.BotConfig, client *horizonclient.Client, sdex *plugins.SDEX, diff --git a/gui/backend/autogenerate_bot.go b/gui/backend/autogenerate_bot.go index 6a9291295..c113caf43 100644 --- a/gui/backend/autogenerate_bot.go +++ b/gui/backend/autogenerate_bot.go @@ -6,11 +6,11 @@ import ( "log" "net/http" - "github.com/stellar/go/build" - "github.com/stellar/go/clients/horizon" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/keypair" + "github.com/stellar/go/network" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/gui/model2" "github.com/stellar/kelp/plugins" "github.com/stellar/kelp/support/kelpos" @@ -99,38 +99,59 @@ func (s *APIServer) autogenerateBot(w http.ResponseWriter, r *http.Request) { } func (s *APIServer) setupAccount(address string, signer string, botName string) error { - _, e := s.checkFundAccount(address, botName) + fundedAccount, e := s.checkFundAccount(address, botName) if e != nil { return fmt.Errorf("error checking and funding account: %s\n", e) } - client := horizon.DefaultTestNetClient - txn, e := build.Transaction( - build.SourceAccount{AddressOrSeed: address}, - build.AutoSequence{SequenceProvider: client}, - build.TestNetwork, - build.Trust("COUPON", "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"), - build.Payment( - build.Destination{AddressOrSeed: address}, - build.CreditAmount{Code: "COUPON", Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", Amount: "1000.0"}, - build.SourceAccount{AddressOrSeed: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, - ), - ) + var txOps []txnbuild.Operation + trustOp := txnbuild.ChangeTrust{ + Line: txnbuild.CreditAsset{Code: "COUPON", + Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + } + txOps = append(txOps, &trustOp) + + paymentOp := txnbuild.Payment{ + Destination: address, + Amount: "1000.0", + Asset: txnbuild.CreditAsset{Code: "COUPON", + Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + SourceAccount: &txnbuild.SimpleAccount{AccountID: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + } + txOps = append(txOps, &paymentOp) + + tx := txnbuild.Transaction{ + SourceAccount: fundedAccount, + Operations: txOps, + Timebounds: txnbuild.NewInfiniteTimeout(), + Network: network.TestNetworkPassphrase, + BaseFee: 100, + } + e = tx.Build() + if e != nil { return fmt.Errorf("cannot create trustline transaction for account %s for bot '%s': %s\n", address, botName, e) } - txnS, e := txn.Sign(signer, issuerSeed) - if e != nil { - return fmt.Errorf("cannot sign trustline transaction for account %s for bot '%s': %s\n", address, botName, e) + for _, s := range []string{signer, issuerSeed} { + kp, e := keypair.Parse(s) + if e != nil { + return fmt.Errorf("cannot parse seed %s required for signing: %s\n", s, e) + } + + e = tx.Sign(kp.(*keypair.Full)) + if e != nil { + return fmt.Errorf("cannot sign trustline transaction for account %s for bot '%s': %s\n", address, botName, e) + } } - txn64, e := txnS.Base64() + txn64, e := tx.Base64() if e != nil { return fmt.Errorf("cannot convert trustline transaction to base64 for account %s for bot '%s': %s\n", address, botName, e) } - resp, e := client.SubmitTransaction(txn64) + client := horizonclient.DefaultTestNetClient + resp, e := client.SubmitTransactionXDR(txn64) if e != nil { return fmt.Errorf("error submitting change trust transaction for address %s for bot '%s': %s\n", address, botName, e) } diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go index 008f7fa12..7360bf998 100644 --- a/gui/backend/upsert_bot_config.go +++ b/gui/backend/upsert_bot_config.go @@ -8,11 +8,13 @@ import ( "net/http" "strings" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizon" + "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/keypair" + "github.com/stellar/go/network" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/strkey" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/gui/model2" "github.com/stellar/kelp/plugins" "github.com/stellar/kelp/support/kelpos" @@ -219,11 +221,11 @@ func (s *APIServer) reinitBotCheck(req upsertBotConfigRequest) { } func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, traderSeed string, botName string, isTestnet bool, assets []hProtocol.Asset) error { - network := build.PublicNetwork - client := horizon.DefaultPublicNetClient + activeNetwork := network.PublicNetworkPassphrase + client := horizonclient.DefaultPublicNetClient if isTestnet { - network = build.TestNetwork - client = horizon.DefaultTestNetClient + activeNetwork = network.TestNetworkPassphrase + client = horizonclient.DefaultTestNetClient } // find trustlines to be added @@ -255,31 +257,50 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, // build txn address := kp.Address() - muts := []build.TransactionMutator{ - build.SourceAccount{AddressOrSeed: address}, - build.AutoSequence{SequenceProvider: client}, - network, + accountReq := horizonclient.AccountRequest{AccountID: address} + account, err := horizonclient.DefaultTestNetClient.AccountDetail(accountReq) + if err != nil { + return fmt.Errorf("Unable to load account for %s\n: %s", address, err) } + + var txOps []txnbuild.Operation for _, a := range trustlines { - muts = append(muts, build.Trust(a.Code, a.Issuer)) + + trustOp := txnbuild.ChangeTrust{ + Line: txnbuild.CreditAsset{Code: a.Code, Issuer: a.Issuer}, + } + txOps = append(txOps, &trustOp) log.Printf("added trust asset operation to transaction for asset: %+v\n", a) } - tx, e := build.Transaction(muts...) + + tx := txnbuild.Transaction{ + SourceAccount: &account, + Operations: txOps, + Timebounds: txnbuild.NewInfiniteTimeout(), + Network: activeNetwork, + BaseFee: 100, + } + e := tx.Build() if e != nil { return fmt.Errorf("cannot create trustline transaction for account %s for bot '%s': %s\n", address, botName, e) } - txnS, e := tx.Sign(traderSeed) + kpSigner, e := keypair.Parse(traderSeed) + if e != nil { + return fmt.Errorf("cannot parse seed %s required for signing: %s\n", traderSeed, e) + } + + e = tx.Sign(kpSigner.(*keypair.Full)) if e != nil { return fmt.Errorf("cannot sign trustline transaction for account %s for bot '%s': %s\n", address, botName, e) } - txn64, e := txnS.Base64() + txn64, e := tx.Base64() if e != nil { return fmt.Errorf("cannot convert trustline transaction to base64 for account %s for bot '%s': %s\n", address, botName, e) } - txSuccess, e := client.SubmitTransaction(txn64) + txSuccess, e := client.SubmitTransactionXDR(txn64) if e != nil { var herr *horizon.Error switch t := e.(type) { diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 911d71f89..7b9c10f1c 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -5,13 +5,13 @@ import ( "log" "math" "reflect" + "strconv" "time" "math/rand" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" - "github.com/stellar/go/xdr" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/utils" @@ -174,12 +174,12 @@ func (b BatchedExchange) GetLatestTradeCursor() (interface{}, error) { } // SubmitOpsSynch is the forced synchronous version of SubmitOps below (same for batchedExchange) -func (b BatchedExchange) SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { +func (b BatchedExchange) SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { return b.SubmitOps(ops, asyncCallback) } // SubmitOps performs any finalization or submission step needed by the exchange -func (b BatchedExchange) SubmitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { +func (b BatchedExchange) SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { var e error b.commands, e = b.Ops2Commands(ops, b.baseAsset, b.quoteAsset) if e != nil { @@ -363,27 +363,34 @@ func convert2Price(number *model.Number) (hProtocol.Price, error) { }, nil } -func assetsEqual(hAsset hProtocol.Asset, xAsset xdr.Asset) (bool, error) { - if xAsset.Type == xdr.AssetTypeAssetTypeNative { +// to do: @Nikhil this method is similar to utils.assetsEqualXDR. Consider removing one? +func assetsEqual(hAsset hProtocol.Asset, txnAsset txnbuild.Asset) (bool, error) { + if txnAsset.IsNative() { return hAsset.Type == utils.Native, nil } else if hAsset.Type == utils.Native { return false, nil } - var xAssetType, xAssetCode, xAssetIssuer string - e := xAsset.Extract(&xAssetType, &xAssetCode, &xAssetIssuer) - if e != nil { - return false, e - } - return xAssetCode == hAsset.Code, nil + return txnAsset.GetCode() == hAsset.Code, nil } // manageOffer2Order converts a manage offer operation to a model.Order -func manageOffer2Order(mob *build.ManageOfferBuilder, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, orderConstraints *model.OrderConstraints) (*model.Order, error) { +func manageOffer2Order(mob *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, orderConstraints *model.OrderConstraints) (*model.Order, error) { orderAction := model.OrderActionSell - price := model.NumberFromFloat(float64(mob.MO.Price.N)/float64(mob.MO.Price.D), largePrecision) - volume := model.NumberFromFloat(float64(mob.MO.Amount)/math.Pow(10, 7), largePrecision) - isBuy, e := assetsEqual(quoteAsset, mob.MO.Selling) + + priceFloat, e := strconv.ParseFloat(mob.Price, 64) + if e != nil { + return nil, fmt.Errorf("could not convert price to float: %s", e) + } + + amountFloat, e := strconv.ParseFloat(mob.Amount, 64) + if e != nil { + return nil, fmt.Errorf("could not convert amount to float: %s", e) + } + + price := model.NumberFromFloat(priceFloat, largePrecision) + volume := model.NumberFromFloat(amountFloat/math.Pow(10, 7), largePrecision) + isBuy, e := assetsEqual(quoteAsset, mob.Selling) if e != nil { return nil, fmt.Errorf("could not compare assets, error: %s", e) } @@ -422,7 +429,7 @@ func order2OpenOrder(order *model.Order, txID *model.TransactionID) *model.OpenO } // Ops2Commands converts... -func (b BatchedExchange) Ops2Commands(ops []build.TransactionMutator, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset) ([]Command, error) { +func (b BatchedExchange) Ops2Commands(ops []txnbuild.Operation, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset) ([]Command, error) { pair := &model.TradingPair{ Base: model.FromHorizonAsset(baseAsset), Quote: model.FromHorizonAsset(quoteAsset), @@ -432,7 +439,7 @@ func (b BatchedExchange) Ops2Commands(ops []build.TransactionMutator, baseAsset // Ops2CommandsHack converts... func Ops2CommandsHack( - ops []build.TransactionMutator, + ops []txnbuild.Operation, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, offerID2OrderID map[int64]string, // if map is nil then we ignore ID errors @@ -441,18 +448,12 @@ func Ops2CommandsHack( commands := []Command{} for _, op := range ops { switch manageOffer := op.(type) { - case *build.ManageOfferBuilder: + case *txnbuild.ManageSellOffer: c, e := op2CommandsHack(manageOffer, baseAsset, quoteAsset, offerID2OrderID, orderConstraints) if e != nil { return nil, fmt.Errorf("unable to convert *build.ManageOfferBuilder to a Command: %s", e) } commands = append(commands, c...) - case build.ManageOfferBuilder: - c, e := op2CommandsHack(&manageOffer, baseAsset, quoteAsset, offerID2OrderID, orderConstraints) - if e != nil { - return nil, fmt.Errorf("unable to convert build.ManageOfferBuilder to a Command: %s", e) - } - commands = append(commands, c...) default: return nil, fmt.Errorf("unable to recognize transaction mutator op (%s): %v", reflect.TypeOf(op), manageOffer) } @@ -462,7 +463,7 @@ func Ops2CommandsHack( // op2CommandsHack converts one op to possibly many Commands func op2CommandsHack( - manageOffer *build.ManageOfferBuilder, + manageOffer *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, offerID2OrderID map[int64]string, // if map is nil then we ignore ID errors @@ -474,12 +475,17 @@ func op2CommandsHack( return nil, fmt.Errorf("error converting from manageOffer op to Order: %s", e) } - if manageOffer.MO.Amount == 0 { + amountFloat, e := strconv.ParseFloat(manageOffer.Amount, 64) + if e != nil { + return nil, fmt.Errorf("could not convert amount to float: %s", e) + } + + if amountFloat == 0 { // cancel // fetch real orderID here (hoops we have to jump through because of the hacked approach to using centralized exchanges) var orderID string if offerID2OrderID != nil { - ID := int64(manageOffer.MO.OfferId) + ID := manageOffer.OfferID var ok bool orderID, ok = offerID2OrderID[ID] if !ok { @@ -491,13 +497,13 @@ func op2CommandsHack( txID := model.MakeTransactionID(orderID) openOrder := order2OpenOrder(order, txID) commands = append(commands, MakeCommandCancel(openOrder)) - } else if manageOffer.MO.OfferId != 0 { + } else if manageOffer.OfferID != 0 { // modify is cancel followed by create // -- cancel // fetch real orderID here (hoops we have to jump through because of the hacked approach to using centralized exchanges) var orderID string if offerID2OrderID != nil { - ID := int64(manageOffer.MO.OfferId) + ID := manageOffer.OfferID var ok bool orderID, ok = offerID2OrderID[ID] if !ok { diff --git a/plugins/composeStrategy.go b/plugins/composeStrategy.go index 359f3e1f4..4eff925fd 100644 --- a/plugins/composeStrategy.go +++ b/plugins/composeStrategy.go @@ -6,9 +6,9 @@ import ( "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/errors" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/support/utils" ) @@ -39,7 +39,7 @@ func makeComposeStrategy( } // PruneExistingOffers impl -func (s *composeStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) { +func (s *composeStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) { pruneOps1, newBuyingAOffers := s.buyStrat.PruneExistingOffers(buyingAOffers) pruneOps2, newSellingAOffers := s.sellStrat.PruneExistingOffers(sellingAOffers) pruneOps1 = append(pruneOps1, pruneOps2...) @@ -71,7 +71,7 @@ func (s *composeStrategy) PreUpdate(maxAssetBase float64, maxAssetQuote float64, func (s *composeStrategy) UpdateWithOps( buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer, -) ([]build.TransactionMutator, error) { +) ([]txnbuild.Operation, error) { // buy side, flip newTopBuyPrice because it will be inverted from this parent strategy's context of base/quote buyOps, newTopBuyPriceInverted, e1 := s.buyStrat.UpdateWithOps(buyingAOffers) newTopBuyPrice := model.InvertNumber(newTopBuyPriceInverted) @@ -79,7 +79,7 @@ func (s *composeStrategy) UpdateWithOps( sellOps, _, e2 := s.sellStrat.UpdateWithOps(sellingAOffers) // check for errors - ops := []build.TransactionMutator{} + ops := []txnbuild.Operation{} if e1 != nil && e2 != nil { return ops, fmt.Errorf("errors on both sides: buying (= %s) and selling (= %s)", e1, e2) } else if e1 != nil { diff --git a/plugins/deleteSideStrategy.go b/plugins/deleteSideStrategy.go index aa6421915..3d07d4b66 100644 --- a/plugins/deleteSideStrategy.go +++ b/plugins/deleteSideStrategy.go @@ -3,8 +3,8 @@ package plugins import ( "log" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" ) @@ -33,9 +33,9 @@ func makeDeleteSideStrategy( } // PruneExistingOffers impl -func (s *deleteSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) { +func (s *deleteSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) { log.Printf("deleteSideStrategy: deleting %d offers\n", len(offers)) - pruneOps := []build.TransactionMutator{} + pruneOps := []txnbuild.Operation{} for i := 0; i < len(offers); i++ { pOp := s.sdex.DeleteOffer(offers[i]) pruneOps = append(pruneOps, &pOp) @@ -49,8 +49,8 @@ func (s *deleteSideStrategy) PreUpdate(maxAssetBase float64, maxAssetQuote float } // UpdateWithOps impl -func (s *deleteSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build.TransactionMutator, newTopOffer *model.Number, e error) { - return []build.TransactionMutator{}, nil, nil +func (s *deleteSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) { + return []txnbuild.Operation{}, nil, nil } // PostUpdate impl diff --git a/plugins/makerModeFilter.go b/plugins/makerModeFilter.go index 08df4f3bc..e55428c32 100644 --- a/plugins/makerModeFilter.go +++ b/plugins/makerModeFilter.go @@ -4,9 +4,10 @@ import ( "fmt" "log" "math" + "strconv" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/utils" @@ -32,7 +33,7 @@ func MakeFilterMakerMode(submitMode api.SubmitMode, exchangeShim api.ExchangeShi var _ SubmitFilter = &makerModeFilter{} -func (f *makerModeFilter) Apply(ops []build.TransactionMutator, sellingOffers []hProtocol.Offer, buyingOffers []hProtocol.Offer) ([]build.TransactionMutator, error) { +func (f *makerModeFilter) Apply(ops []txnbuild.Operation, sellingOffers []hProtocol.Offer, buyingOffers []hProtocol.Offer) ([]txnbuild.Operation, error) { ob, e := f.exchangeShim.GetOrderBook(f.tradingPair, 50) if e != nil { return nil, fmt.Errorf("could not fetch orderbook: %s", e) @@ -110,11 +111,11 @@ func (f *makerModeFilter) topOrderPriceExcludingTrader(obSide []model.Order, tra } func (f *makerModeFilter) filterOps( - ops []build.TransactionMutator, + ops []txnbuild.Operation, ob *model.OrderBook, sellingOffers []hProtocol.Offer, buyingOffers []hProtocol.Offer, -) ([]build.TransactionMutator, error) { +) ([]txnbuild.Operation, error) { baseAsset, quoteAsset, e := f.sdex.Assets() if e != nil { return nil, fmt.Errorf("could not get assets: %s", e) @@ -132,21 +133,16 @@ func (f *makerModeFilter) filterOps( numKeep := 0 numDropped := 0 numTransformed := 0 - filteredOps := []build.TransactionMutator{} + filteredOps := []txnbuild.Operation{} for _, op := range ops { - var newOp build.TransactionMutator + var newOp txnbuild.Operation var keep bool switch o := op.(type) { - case *build.ManageOfferBuilder: + case *txnbuild.ManageSellOffer: newOp, keep, e = f.transformOfferMakerMode(baseAsset, quoteAsset, topBidPrice, topAskPrice, o) if e != nil { return nil, fmt.Errorf("could not transform offer (pointer case): %s", e) } - case build.ManageOfferBuilder: - newOp, keep, e = f.transformOfferMakerMode(baseAsset, quoteAsset, topBidPrice, topAskPrice, &o) - if e != nil { - return nil, fmt.Errorf("could not check transform offer (non-pointer case): %s", e) - } default: newOp = o keep = true @@ -178,19 +174,29 @@ func (f *makerModeFilter) transformOfferMakerMode( quoteAsset hProtocol.Asset, topBidPrice *model.Number, topAskPrice *model.Number, - op *build.ManageOfferBuilder, -) (*build.ManageOfferBuilder, bool, error) { + op *txnbuild.ManageSellOffer, +) (*txnbuild.ManageSellOffer, bool, error) { + //represent amount as float + amountFloat, e := strconv.ParseFloat(op.Amount, 64) + if e != nil { + return nil, false, fmt.Errorf("could not convert amount to float: %s", e) + } + // delete operations should never be dropped - if op.MO.Amount == 0 { + if amountFloat == 0 { return op, true, nil } - isSell, e := utils.IsSelling(baseAsset, quoteAsset, op.MO.Selling, op.MO.Buying) + isSell, e := utils.IsSelling(baseAsset, quoteAsset, op.Selling, op.Buying) if e != nil { return nil, false, fmt.Errorf("error when running the isSelling check: %s", e) } - sellPrice := float64(op.MO.Price.N) / float64(op.MO.Price.D) + sellPrice, e := strconv.ParseFloat(op.Price, 64) + if e != nil { + return nil, false, fmt.Errorf("could not convert price to float: %s", e) + } + var keep bool if !isSell && topAskPrice != nil { // invert price when buying @@ -215,14 +221,14 @@ func (f *makerModeFilter) transformOfferMakerMode( } // figure out how to convert the offer to a dropped state - if op.MO.OfferId == 0 { + if op.OfferID == 0 { // new offers can be dropped return nil, false, nil - } else if op.MO.Amount != 0 { + } else if amountFloat != 0 { // modify offers should be converted to delete offers opCopy := *op - opCopy.MO.Amount = 0 + opCopy.Amount = "0" return &opCopy, false, nil } - return nil, keep, fmt.Errorf("unable to transform manageOffer operation: offerID=%d, amount=%.7f, price=%.7f", op.MO.OfferId, float64(op.MO.Amount)/math.Pow(10, 7), sellPrice) + return nil, keep, fmt.Errorf("unable to transform manageOffer operation: offerID=%d, amount=%.7f, price=%.7f", op.OfferID, amountFloat/math.Pow(10, 7), sellPrice) } diff --git a/plugins/mirrorStrategy.go b/plugins/mirrorStrategy.go index 10f586c64..fe58437dc 100644 --- a/plugins/mirrorStrategy.go +++ b/plugins/mirrorStrategy.go @@ -5,8 +5,8 @@ import ( "log" "sync" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/toml" @@ -192,8 +192,8 @@ func makeMirrorStrategy(sdex *SDEX, ieif *IEIF, pair *model.TradingPair, baseAss } // PruneExistingOffers deletes any extra offers -func (s *mirrorStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) { - return []build.TransactionMutator{}, buyingAOffers, sellingAOffers +func (s *mirrorStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) { + return []txnbuild.Operation{}, buyingAOffers, sellingAOffers } // PreUpdate changes the strategy's state in prepration for the update @@ -230,7 +230,7 @@ func (s *mirrorStrategy) recordBalances() error { func (s *mirrorStrategy) UpdateWithOps( buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer, -) ([]build.TransactionMutator, error) { +) ([]txnbuild.Operation, error) { ob, e := s.exchange.GetOrderBook(s.backingPair, s.orderbookDepth) if e != nil { return nil, e @@ -286,7 +286,7 @@ func (s *mirrorStrategy) UpdateWithOps( } log.Printf("num. sellOps in this update: %d\n", len(sellOps)) - ops := []build.TransactionMutator{} + ops := []txnbuild.Operation{} if len(ob.Bids()) > 0 && len(sellingAOffers) > 0 && ob.Bids()[0].Price.AsFloat() >= utils.PriceAsFloat(sellingAOffers[0].Price) { ops = append(ops, sellOps...) ops = append(ops, buyOps...) @@ -301,14 +301,14 @@ func (s *mirrorStrategy) UpdateWithOps( func (s *mirrorStrategy) updateLevels( oldOffers []hProtocol.Offer, newOrders []model.Order, - modifyOffer func(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error), - createOffer func(baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error), + modifyOffer func(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error), + createOffer func(baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error), priceMultiplier float64, hackPriceInvertForBuyOrderChangeCheck bool, // needed because createBuy and modBuy inverts price so we need this for price comparison in doModifyOffer bc balanceCoordinator, -) ([]build.TransactionMutator, error) { - ops := []build.TransactionMutator{} - deleteOps := []build.TransactionMutator{} +) ([]txnbuild.Operation, error) { + ops := []txnbuild.Operation{} + deleteOps := []txnbuild.Operation{} if len(newOrders) >= len(oldOffers) { for i := 0; i < len(oldOffers); i++ { modifyOp, deleteOp, e := s.doModifyOffer(oldOffers[i], newOrders[i], priceMultiplier, modifyOffer, hackPriceInvertForBuyOrderChangeCheck) @@ -346,7 +346,7 @@ func (s *mirrorStrategy) updateLevels( return nil, e } if mo != nil { - ops = append(ops, *mo) + ops = append(ops, mo) // update the cached liabilities if we create a valid operation to create an offer if hackPriceInvertForBuyOrderChangeCheck { s.ieif.AddLiabilities(*s.quoteAsset, *s.baseAsset, vol.Multiply(*price).AsFloat(), vol.AsFloat(), incrementalNativeAmountRaw) @@ -375,7 +375,7 @@ func (s *mirrorStrategy) updateLevels( // delete remaining prior offers for i := len(newOrders); i < len(oldOffers); i++ { deleteOp := s.sdex.DeleteOffer(oldOffers[i]) - deleteOps = append(deleteOps, deleteOp) + deleteOps = append(deleteOps, &deleteOp) } } @@ -391,9 +391,9 @@ func (s *mirrorStrategy) doModifyOffer( oldOffer hProtocol.Offer, newOrder model.Order, priceMultiplier float64, - modifyOffer func(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error), + modifyOffer func(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error), hackPriceInvertForBuyOrderChangeCheck bool, // needed because createBuy and modBuy inverts price so we need this for price comparison in doModifyOffer -) (build.TransactionMutator, build.TransactionMutator, error) { +) (txnbuild.Operation, txnbuild.Operation, error) { price := newOrder.Price.Scale(priceMultiplier) vol := newOrder.Volume.Scale(1.0 / s.volumeDivideBy) oldPrice := model.MustNumberFromString(oldOffer.Price, s.primaryConstraints.PricePrecision) @@ -423,7 +423,7 @@ func (s *mirrorStrategy) doModifyOffer( log.Printf("deleting level, baseVolume (%f) on backing exchange dropped below minBaseVolume of backing exchange (%f)\n", offerAmount.AsFloat(), s.backingConstraints.MinBaseVolume.AsFloat()) deleteOp := s.sdex.DeleteOffer(oldOffer) - return nil, deleteOp, nil + return nil, &deleteOp, nil } mo, e := modifyOffer( oldOffer, @@ -441,12 +441,12 @@ func (s *mirrorStrategy) doModifyOffer( } else { s.ieif.AddLiabilities(oldOffer.Selling, oldOffer.Buying, offerAmount.AsFloat(), offerAmount.Multiply(*offerPrice).AsFloat(), incrementalNativeAmountRaw) } - return *mo, nil, nil + return mo, nil, nil } // since mo is nil we want to delete this offer deleteOp := s.sdex.DeleteOffer(oldOffer) - return nil, deleteOp, nil + return nil, &deleteOp, nil } // PostUpdate changes the strategy's state after the update has taken place diff --git a/plugins/orderConstraintsFilter.go b/plugins/orderConstraintsFilter.go index 8888208b1..7d3c1805a 100644 --- a/plugins/orderConstraintsFilter.go +++ b/plugins/orderConstraintsFilter.go @@ -4,9 +4,10 @@ import ( "fmt" "log" "math" + "strconv" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/utils" ) @@ -34,51 +35,50 @@ func MakeFilterOrderConstraints( // Apply impl. func (f *orderConstraintsFilter) Apply( - ops []build.TransactionMutator, + ops []txnbuild.Operation, sellingOffers []hProtocol.Offer, buyingOffers []hProtocol.Offer, -) ([]build.TransactionMutator, error) { +) ([]txnbuild.Operation, error) { numKeep := 0 numDropped := 0 - filteredOps := []build.TransactionMutator{} + filteredOps := []txnbuild.Operation{} for _, op := range ops { var keep bool var e error - var opPtr *build.ManageOfferBuilder + var opPtr *txnbuild.ManageSellOffer switch o := op.(type) { - case *build.ManageOfferBuilder: + case *txnbuild.ManageSellOffer: keep, e = f.shouldKeepOffer(o) if e != nil { return nil, fmt.Errorf("could not transform offer (pointer case): %s", e) } opPtr = o - case build.ManageOfferBuilder: - keep, e = f.shouldKeepOffer(&o) - if e != nil { - return nil, fmt.Errorf("could not check transform offer (non-pointer case): %s", e) - } - opPtr = &o default: keep = true } + amountFloat, e := strconv.ParseFloat(opPtr.Amount, 64) + if e != nil { + return nil, fmt.Errorf("could not convert amount to float: %s", e) + } + if keep { filteredOps = append(filteredOps, opPtr) numKeep++ } else { numDropped++ // figure out how to convert the offer to a dropped state - if opPtr.MO.OfferId == 0 { + if opPtr.OfferID == 0 { // new offers can be dropped, so don't add to filteredOps - } else if opPtr.MO.Amount != 0 { + } else if amountFloat != 0 { // modify offers should be converted to delete offers opCopy := *opPtr - opCopy.MO.Amount = 0 - filteredOps = append(filteredOps, opCopy) + opCopy.Amount = "0" + filteredOps = append(filteredOps, &opCopy) } else { - return nil, fmt.Errorf("unable to drop manageOffer operation (probably a delete op that should not have reached here): offerID=%d, amountRaw=%.8f", opPtr.MO.OfferId, float64(opPtr.MO.Amount)) + return nil, fmt.Errorf("unable to drop manageOffer operation (probably a delete op that should not have reached here): offerID=%d, amountRaw=%.8f", opPtr.OfferID, amountFloat) } } } @@ -87,20 +87,28 @@ func (f *orderConstraintsFilter) Apply( return filteredOps, nil } -func (f *orderConstraintsFilter) shouldKeepOffer(op *build.ManageOfferBuilder) (bool, error) { +func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) (bool, error) { // delete operations should never be dropped - if op.MO.Amount == 0 { + amountFloat, e := strconv.ParseFloat(op.Amount, 64) + if e != nil { + return false, fmt.Errorf("could not convert amount to float: %s", e) + } + if amountFloat == 0 { return true, nil } - isSell, e := utils.IsSelling(f.baseAsset, f.quoteAsset, op.MO.Selling, op.MO.Buying) + isSell, e := utils.IsSelling(f.baseAsset, f.quoteAsset, op.Selling, op.Buying) if e != nil { return false, fmt.Errorf("error when running the isSelling check: %s", e) } - sellPrice := float64(op.MO.Price.N) / float64(op.MO.Price.D) + sellPrice, e := strconv.ParseFloat(op.Price, 64) + if e != nil { + return false, fmt.Errorf("could not convert price to float: %s", e) + } + if isSell { - baseAmount := float64(op.MO.Amount) / math.Pow(10, 7) + baseAmount := amountFloat / math.Pow(10, 7) quoteAmount := baseAmount * sellPrice if baseAmount < f.oc.MinBaseVolume.AsFloat() { log.Printf("orderConstraintsFilter: selling, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString()) @@ -115,7 +123,7 @@ func (f *orderConstraintsFilter) shouldKeepOffer(op *build.ManageOfferBuilder) ( } // buying - quoteAmount := float64(op.MO.Amount) / math.Pow(10, 7) + quoteAmount := amountFloat / math.Pow(10, 7) baseAmount := quoteAmount * sellPrice if baseAmount < f.oc.MinBaseVolume.AsFloat() { log.Printf("orderConstraintsFilter: buying, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString()) diff --git a/plugins/priceFeed.go b/plugins/priceFeed.go index b6ddb216e..776aecdf1 100644 --- a/plugins/priceFeed.go +++ b/plugins/priceFeed.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" @@ -14,14 +13,14 @@ import ( type privateSdexHack struct { API *horizonclient.Client Ieif *IEIF - Network build.Network + Network string } // privateSdexHackVar is a temporary hack variable for SDEX price feeds pending refactor var privateSdexHackVar *privateSdexHack // SetPrivateSdexHack sets the privateSdexHack variable which is temporary until the pending SDEX price feed refactor -func SetPrivateSdexHack(api *horizonclient.Client, ieif *IEIF, network build.Network) error { +func SetPrivateSdexHack(api *horizonclient.Client, ieif *IEIF, network string) error { if privateSdexHackVar != nil { return fmt.Errorf("privateSdexHack is already set: %+v", privateSdexHackVar) } diff --git a/plugins/sdex.go b/plugins/sdex.go index 84fc4a38c..6866dee8c 100644 --- a/plugins/sdex.go +++ b/plugins/sdex.go @@ -12,9 +12,9 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" "github.com/pkg/errors" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/networking" @@ -38,7 +38,7 @@ type SDEX struct { TradingAccount string SourceSeed string TradingSeed string - Network build.Network + Network string threadTracker *multithreading.ThreadTracker operationalBuffer float64 operationalBufferNonNativePct float64 @@ -77,7 +77,7 @@ func MakeSDEX( tradingSeed string, sourceAccount string, tradingAccount string, - network build.Network, + network string, threadTracker *multithreading.ThreadTracker, operationalBuffer float64, operationalBufferNonNativePct float64, @@ -111,7 +111,7 @@ func MakeSDEX( // TODO 2 remove this hack, we need to find a way of having ieif get a handle to compute balances or always compute and pass balances in? ieif.SetExchangeShim(exchangeShim) - log.Printf("Using network passphrase: %s\n", sdex.Network.Passphrase) + log.Printf("Using network passphrase: %s\n", sdex.Network) if sdex.SourceAccount == "" { sdex.SourceAccount = sdex.TradingAccount @@ -185,8 +185,8 @@ func (sdex *SDEX) OverrideOrderConstraints(pair *model.TradingPair, override *mo } // DeleteAllOffers is a helper that accumulates delete operations for the passed in offers -func (sdex *SDEX) DeleteAllOffers(offers []hProtocol.Offer) []build.TransactionMutator { - ops := []build.TransactionMutator{} +func (sdex *SDEX) DeleteAllOffers(offers []hProtocol.Offer) []txnbuild.Operation { + ops := []txnbuild.Operation{} for _, offer := range offers { op := sdex.DeleteOffer(offer) ops = append(ops, &op) @@ -195,31 +195,34 @@ func (sdex *SDEX) DeleteAllOffers(offers []hProtocol.Offer) []build.TransactionM } // DeleteOffer returns the op that needs to be submitted to the network in order to delete the passed in offer -func (sdex *SDEX) DeleteOffer(offer hProtocol.Offer) build.ManageOfferBuilder { - rate := build.Rate{ - Selling: utils.Asset2Asset(offer.Selling), - Buying: utils.Asset2Asset(offer.Buying), - Price: build.Price(offer.Price), +func (sdex *SDEX) DeleteOffer(offer hProtocol.Offer) txnbuild.ManageSellOffer { + var result txnbuild.ManageSellOffer + var err error + if sdex.SourceAccount == sdex.TradingAccount { + result, err = txnbuild.DeleteOfferOp(offer.ID) + } else { + result, err = txnbuild.DeleteOfferOp(offer.ID, &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount}) } - if sdex.SourceAccount == sdex.TradingAccount { - return build.ManageOffer(false, build.Amount("0"), rate, build.OfferID(offer.ID)) + if err != nil { + // to do: log or return error + return txnbuild.ManageSellOffer{} } - return build.ManageOffer(false, build.Amount("0"), rate, build.OfferID(offer.ID), build.SourceAccount{AddressOrSeed: sdex.TradingAccount}) + return result } // ModifyBuyOffer modifies a buy offer -func (sdex *SDEX) ModifyBuyOffer(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { +func (sdex *SDEX) ModifyBuyOffer(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { return sdex.ModifySellOffer(offer, 1/price, amount*price, incrementalNativeAmountRaw) } // ModifySellOffer modifies a sell offer -func (sdex *SDEX) ModifySellOffer(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { +func (sdex *SDEX) ModifySellOffer(offer hProtocol.Offer, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { return sdex.createModifySellOffer(&offer, offer.Selling, offer.Buying, price, amount, incrementalNativeAmountRaw) } // CreateSellOffer creates a sell offer -func (sdex *SDEX) CreateSellOffer(base hProtocol.Asset, counter hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { +func (sdex *SDEX) CreateSellOffer(base hProtocol.Asset, counter hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { return sdex.createModifySellOffer(nil, base, counter, price, amount, incrementalNativeAmountRaw) } @@ -294,7 +297,7 @@ func (sdex *SDEX) ComputeIncrementalNativeAmountRaw(isNewOffer bool) float64 { } // createModifySellOffer is the main method that handles the logic of creating or modifying an offer, note that all offers are treated as sell offers in Stellar -func (sdex *SDEX) createModifySellOffer(offer *hProtocol.Offer, selling hProtocol.Asset, buying hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { +func (sdex *SDEX) createModifySellOffer(offer *hProtocol.Offer, selling hProtocol.Asset, buying hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { if price <= 0 { return nil, fmt.Errorf("error: cannot create or modify offer, invalid price: %.8f", price) } @@ -338,60 +341,59 @@ func (sdex *SDEX) createModifySellOffer(offer *hProtocol.Offer, selling hProtoco } stringPrice := strconv.FormatFloat(price, 'f', int(sdexOrderConstraints.PricePrecision), 64) - rate := build.Rate{ - Selling: utils.Asset2Asset(selling), - Buying: utils.Asset2Asset(buying), - Price: build.Price(stringPrice), - } + stringAmount := strconv.FormatFloat(amount, 'f', int(sdexOrderConstraints.VolumePrecision), 64) - mutators := []interface{}{ - rate, - build.Amount(strconv.FormatFloat(amount, 'f', int(sdexOrderConstraints.VolumePrecision), 64)), + result, err := txnbuild.CreateOfferOp(utils.Asset2Asset(selling), utils.Asset2Asset(buying), stringAmount, stringPrice) + if err != nil { + return nil, err } + if offer != nil { - mutators = append(mutators, build.OfferID(offer.ID)) + result.OfferID = offer.ID } if sdex.SourceAccount != sdex.TradingAccount { - mutators = append(mutators, build.SourceAccount{AddressOrSeed: sdex.TradingAccount}) + result.SourceAccount = &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount} } - result := build.ManageOffer(false, mutators...) + return &result, nil } // SubmitOpsSynch is the forced synchronous version of SubmitOps below -func (sdex *SDEX) SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { +func (sdex *SDEX) SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { return sdex.submitOps(ops, asyncCallback, false) } // SubmitOps submits the passed in operations to the network asynchronously in a single transaction -func (sdex *SDEX) SubmitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { +func (sdex *SDEX) SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { return sdex.submitOps(ops, asyncCallback, true) } // submitOps submits the passed in operations to the network in a single transaction. Asynchronous or not based on flag. -func (sdex *SDEX) submitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error), asyncMode bool) error { +func (sdex *SDEX) submitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error), asyncMode bool) error { sdex.incrementSeqNum() - muts := []build.TransactionMutator{ - build.Sequence{Sequence: sdex.seqNum}, - sdex.Network, - build.SourceAccount{AddressOrSeed: sdex.SourceAccount}, + tx := txnbuild.Transaction{ + //Note: sequence number is decremented here because Transaction.Build auto increments sequence number + // To do: @Nikhil confirm if this works as intended. + SourceAccount: &txnbuild.SimpleAccount{AccountID: sdex.SourceAccount, + Sequence: int64(sdex.seqNum - 1)}, + Operations: ops, + Timebounds: txnbuild.NewInfiniteTimeout(), + Network: sdex.Network, } + // compute fee per operation opFee, e := sdex.opFeeStroopsFn() if e != nil { return fmt.Errorf("SubmitOps error when computing op fee: %s", e) } - muts = append(muts, build.BaseFee{Amount: opFee}) - // add transaction mutators - muts = append(muts, ops...) - - tx, e := build.Transaction(muts...) + tx.BaseFee = uint32(opFee) + e = tx.Build() if e != nil { return errors.Wrap(e, "SubmitOps error: ") } // convert to xdr string - txeB64, e := sdex.sign(tx) + txeB64, e := sdex.sign(&tx) if e != nil { return e } @@ -419,24 +421,22 @@ func (sdex *SDEX) submitOps(ops []build.TransactionMutator, asyncCallback func(h } // CreateBuyOffer creates a buy offer -func (sdex *SDEX) CreateBuyOffer(base hProtocol.Asset, counter hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { +func (sdex *SDEX) CreateBuyOffer(base hProtocol.Asset, counter hProtocol.Asset, price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { return sdex.CreateSellOffer(counter, base, 1/price, amount*price, incrementalNativeAmountRaw) } -func (sdex *SDEX) sign(tx *build.TransactionBuilder) (string, error) { - var txe build.TransactionEnvelopeBuilder +func (sdex *SDEX) sign(tx *txnbuild.Transaction) (string, error) { var e error - if sdex.SourceSeed != sdex.TradingSeed { - txe, e = tx.Sign(sdex.SourceSeed, sdex.TradingSeed) + e = utils.SignWithSeed(tx, sdex.SourceSeed, sdex.TradingSeed) } else { - txe, e = tx.Sign(sdex.SourceSeed) + e = utils.SignWithSeed(tx, sdex.SourceSeed) } if e != nil { return "", e } - return txe.Base64() + return tx.Base64() } func (sdex *SDEX) submit(txeB64 string, asyncCallback func(hash string, e error), asyncMode bool) { diff --git a/plugins/sdexFeed.go b/plugins/sdexFeed.go index fd9c3d5e7..189142891 100644 --- a/plugins/sdexFeed.go +++ b/plugins/sdexFeed.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" + sdkNetwork "github.com/stellar/go/network" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" @@ -46,7 +46,7 @@ func makeSDEXFeed(url string) (*sdexFeed, error) { var api *horizonclient.Client var ieif *IEIF - var network build.Network + var network string if privateSdexHackVar != nil { api = privateSdexHackVar.API ieif = privateSdexHackVar.Ieif @@ -55,7 +55,7 @@ func makeSDEXFeed(url string) (*sdexFeed, error) { // use production network by default api = horizonclient.DefaultPublicNetClient ieif = MakeIEIF(true) - network = build.PublicNetwork + network = sdkNetwork.PublicNetworkPassphrase } sdex := MakeSDEX( diff --git a/plugins/sellSideStrategy.go b/plugins/sellSideStrategy.go index d523124a3..34ca8011e 100644 --- a/plugins/sellSideStrategy.go +++ b/plugins/sellSideStrategy.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/support/utils" @@ -67,11 +67,11 @@ func makeSellSideStrategy( } // PruneExistingOffers impl -func (s *sellSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) { +func (s *sellSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) { // figure out which offers we want to prune shouldPrune := computeOffersToPrune(offers, s.currentLevels) - pruneOps := []build.TransactionMutator{} + pruneOps := []txnbuild.Operation{} updatedOffers := []hProtocol.Offer{} for i, offer := range offers { isPruning := shouldPrune[i] @@ -209,12 +209,12 @@ func (s *sellSideStrategy) createPrecedingOffers( ) ( int, // numLevelsConsumed bool, // hitCapacityLimit - []build.TransactionMutator, // ops + []txnbuild.Operation, // ops *model.Number, // newTopOffer error, // e ) { hitCapacityLimit := false - ops := []build.TransactionMutator{} + ops := []txnbuild.Operation{} var newTopOffer *model.Number for i := 0; i < len(precedingLevels); i++ { @@ -230,7 +230,7 @@ func (s *sellSideStrategy) createPrecedingOffers( } var offerPrice *model.Number - var op *build.ManageOfferBuilder + var op *txnbuild.ManageSellOffer offerPrice, hitCapacityLimit, op, e = s.createSellLevel(i, *targetPrice, *targetAmount) if e != nil { return 0, false, nil, nil, fmt.Errorf("unable to create new preceding offer: %s", e) @@ -251,8 +251,8 @@ func (s *sellSideStrategy) createPrecedingOffers( } // UpdateWithOps impl -func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build.TransactionMutator, newTopOffer *model.Number, e error) { - deleteOps := []build.TransactionMutator{} +func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) { + deleteOps := []txnbuild.Operation{} // first we want to re-create any offers that precede our existing offers and are additions to the existing offers that we have precedingLevels := computePrecedingLevels(offers, s.currentLevels) @@ -276,7 +276,7 @@ func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build. if isModify { delOp := s.sdex.DeleteOffer(offers[i]) log.Printf("deleting offer because we previously hit the capacity limit, offerId=%d\n", offers[i].ID) - deleteOps = append(deleteOps, delOp) + deleteOps = append(deleteOps, &delOp) continue } else { // we can break because we would never see a modify operation happen after a non-modify operation @@ -291,7 +291,7 @@ func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build. } var offerPrice *model.Number - var op *build.ManageOfferBuilder + var op *txnbuild.ManageSellOffer if isModify { offerPrice, hitCapacityLimit, op, e = s.modifySellLevel(offers, i, *targetPrice, *targetAmount) } else { @@ -305,7 +305,7 @@ func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build. hitCapacityLimitModify := isModify && hitCapacityLimit if reducedOrderSize || hitCapacityLimitModify { // prepend operations that reduce the size of an existing order because they decrease our liabilities - ops = append([]build.TransactionMutator{op}, ops...) + ops = append([]txnbuild.Operation{op}, ops...) } else { ops = append(ops, op) } @@ -366,7 +366,7 @@ func (s *sellSideStrategy) computeRemainderAmount(incrementalSellAmount float64, } // createSellLevel returns offerPrice, hitCapacityLimit, op, error. -func (s *sellSideStrategy) createSellLevel(index int, targetPrice model.Number, targetAmount model.Number) (*model.Number, bool, *build.ManageOfferBuilder, error) { +func (s *sellSideStrategy) createSellLevel(index int, targetPrice model.Number, targetAmount model.Number) (*model.Number, bool, *txnbuild.ManageSellOffer, error) { incrementalNativeAmountRaw := s.sdex.ComputeIncrementalNativeAmountRaw(true) targetPrice = *model.NumberByCappingPrecision(&targetPrice, s.orderConstraints.PricePrecision) targetAmount = *model.NumberByCappingPrecision(&targetAmount, s.orderConstraints.VolumePrecision) @@ -375,7 +375,7 @@ func (s *sellSideStrategy) createSellLevel(index int, targetPrice model.Number, targetPrice.AsFloat(), targetAmount.AsFloat(), incrementalNativeAmountRaw, - func(price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { + func(price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { priceLogged := price amountLogged := amount if s.divideAmountByPrice { @@ -392,7 +392,7 @@ func (s *sellSideStrategy) createSellLevel(index int, targetPrice model.Number, } // modifySellLevel returns offerPrice, hitCapacityLimit, op, error. -func (s *sellSideStrategy) modifySellLevel(offers []hProtocol.Offer, index int, targetPrice model.Number, targetAmount model.Number) (*model.Number, bool, *build.ManageOfferBuilder, error) { +func (s *sellSideStrategy) modifySellLevel(offers []hProtocol.Offer, index int, targetPrice model.Number, targetAmount model.Number) (*model.Number, bool, *txnbuild.ManageSellOffer, error) { highestPrice := targetPrice.AsFloat() + targetPrice.AsFloat()*s.priceTolerance lowestPrice := targetPrice.AsFloat() - targetPrice.AsFloat()*s.priceTolerance minAmount := targetAmount.AsFloat() - targetAmount.AsFloat()*s.amountTolerance @@ -419,7 +419,7 @@ func (s *sellSideStrategy) modifySellLevel(offers []hProtocol.Offer, index int, targetPrice.AsFloat(), targetAmount.AsFloat(), incrementalNativeAmountRaw, - func(price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error) { + func(price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error) { priceLogged := price amountLogged := amount curPriceLogged := curPrice @@ -454,10 +454,10 @@ func (s *sellSideStrategy) placeOrderWithRetry( targetPrice float64, targetAmount float64, incrementalNativeAmountRaw float64, - placeOffer func(price float64, amount float64, incrementalNativeAmountRaw float64) (*build.ManageOfferBuilder, error), + placeOffer func(price float64, amount float64, incrementalNativeAmountRaw float64) (*txnbuild.ManageSellOffer, error), assetBase hProtocol.Asset, assetQuote hProtocol.Asset, -) (bool, *build.ManageOfferBuilder, error) { +) (bool, *txnbuild.ManageSellOffer, error) { op, e := placeOffer(targetPrice, targetAmount, incrementalNativeAmountRaw) if e != nil { return false, nil, e diff --git a/plugins/submitFilter.go b/plugins/submitFilter.go index 4de310a03..e47269c4d 100644 --- a/plugins/submitFilter.go +++ b/plugins/submitFilter.go @@ -1,15 +1,15 @@ package plugins import ( - "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" ) // SubmitFilter allows you to filter out operations before submitting to the network type SubmitFilter interface { Apply( - ops []build.TransactionMutator, + ops []txnbuild.Operation, sellingOffers []hProtocol.Offer, // quoted quote/base buyingOffers []hProtocol.Offer, // quoted base/quote - ) ([]build.TransactionMutator, error) + ) ([]txnbuild.Operation, error) } diff --git a/support/utils/functions.go b/support/utils/functions.go index 1b1b7e3ae..4590008d7 100644 --- a/support/utils/functions.go +++ b/support/utils/functions.go @@ -11,12 +11,12 @@ import ( "strings" "time" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/keypair" + "github.com/stellar/go/network" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/protocols/horizon/base" - "github.com/stellar/go/xdr" + "github.com/stellar/go/txnbuild" ) // Common Utilities needed by various bots @@ -88,25 +88,21 @@ func GetInvertedPrice(offer hProtocol.Offer) float64 { return PriceAsFloat(big.NewRat(int64(offer.PriceR.D), int64(offer.PriceR.N)).FloatString(10)) } -// Asset2Asset is a Boyz2Men cover band on the blockchain -func Asset2Asset(Asset hProtocol.Asset) build.Asset { - a := build.Asset{} - - a.Code = Asset.Code - a.Issuer = Asset.Issuer +// Asset2Asset converts a horizon.Asset to a txnbuild.Asset. +func Asset2Asset(Asset hProtocol.Asset) txnbuild.Asset { if Asset.Type == Native { - a.Native = true + return txnbuild.NativeAsset{} } - return a + return txnbuild.CreditAsset{Code: Asset.Code, Issuer: Asset.Issuer} } -// Asset2Asset2 converts a build.Asset to a horizon.Asset -func Asset2Asset2(Asset build.Asset) hProtocol.Asset { +// Asset2Asset2 converts a txnbuild.Asset to a horizon.Asset. +func Asset2Asset2(Asset txnbuild.Asset) hProtocol.Asset { a := hProtocol.Asset{} - a.Code = Asset.Code - a.Issuer = Asset.Issuer - if Asset.Native { + a.Code = Asset.GetCode() + a.Issuer = Asset.GetIssuer() + if Asset.IsNative() { a.Type = Native } else if len(a.Code) > 4 { a.Type = "credit_alphanum12" @@ -135,9 +131,9 @@ func Asset2CodeString(asset hProtocol.Asset) string { // String2Asset converts a code:issuer to a horizon.Asset func String2Asset(code string, issuer string) hProtocol.Asset { if code == "XLM" { - return Asset2Asset2(build.NativeAsset()) + return Asset2Asset2(txnbuild.NativeAsset{}) } - return Asset2Asset2(build.CreditAsset(code, issuer)) + return Asset2Asset2(txnbuild.CreditAsset{Code: code, Issuer: issuer}) } // LoadAllOffers loads all the offers for a given account @@ -197,11 +193,11 @@ func ParseSecret(secret string) (*string, error) { } // ParseNetwork checks the horizon url and returns the test network if it contains "test" -func ParseNetwork(horizonURL string) build.Network { +func ParseNetwork(horizonURL string) string { if strings.Contains(horizonURL, "test") { - return build.TestNetwork + return network.TestNetworkPassphrase } - return build.PublicNetwork + return network.PublicNetworkPassphrase } // GetJSON is a helper method to get json from a URL @@ -266,31 +262,26 @@ func ParseAsset(code string, issuer string) (*hProtocol.Asset, error) { } if code == "XLM" { - asset := Asset2Asset2(build.NativeAsset()) + asset := Asset2Asset2(txnbuild.NativeAsset{}) return &asset, nil } - asset := Asset2Asset2(build.CreditAsset(code, issuer)) + asset := Asset2Asset2(txnbuild.CreditAsset{Code: code, Issuer: issuer}) return &asset, nil } -func assetEqualsXDR(hAsset hProtocol.Asset, xAsset xdr.Asset) (bool, error) { - if xAsset.Type == xdr.AssetTypeAssetTypeNative { +func assetEqualsXDR(hAsset hProtocol.Asset, xAsset txnbuild.Asset) (bool, error) { + if xAsset.IsNative() { return hAsset.Type == Native, nil } else if hAsset.Type == Native { return false, nil } - var xAssetType, xAssetCode, xAssetIssuer string - e := xAsset.Extract(&xAssetType, &xAssetCode, &xAssetIssuer) - if e != nil { - return false, fmt.Errorf("could not extract asset information from xdr.Asset: %s", e) - } - return xAssetCode == hAsset.Code && xAssetIssuer == hAsset.Issuer, nil + return xAsset.GetCode() == hAsset.Code && xAsset.GetIssuer() == hAsset.Issuer, nil } // IsSelling helper method -func IsSelling(sdexBase hProtocol.Asset, sdexQuote hProtocol.Asset, selling xdr.Asset, buying xdr.Asset) (bool, error) { +func IsSelling(sdexBase hProtocol.Asset, sdexQuote hProtocol.Asset, selling txnbuild.Asset, buying txnbuild.Asset) (bool, error) { sellingBase, e := assetEqualsXDR(sdexBase, selling) if e != nil { return false, fmt.Errorf("error comparing sdexBase with selling asset") @@ -326,3 +317,19 @@ func Shuffle(slice []string) { slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1] } } + +func SignWithSeed(tx *txnbuild.Transaction, seeds ...string) error { + for _, s := range seeds { + kp, e := keypair.Parse(s) + if e != nil { + return e + } + + e = tx.Sign(kp.(*keypair.Full)) + if e != nil { + return e + } + } + + return nil +} diff --git a/terminator/terminator.go b/terminator/terminator.go index 15827676e..ddacccc9d 100644 --- a/terminator/terminator.go +++ b/terminator/terminator.go @@ -7,9 +7,9 @@ import ( "strconv" "time" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/model" "github.com/stellar/kelp/plugins" "github.com/stellar/kelp/support/utils" @@ -96,8 +96,12 @@ func (t *Terminator) run() { // update data to reflect a successful return from terminator newTimestamp := time.Now().UnixNano() / 1000000 tsMillisStr := fmt.Sprintf("%d", newTimestamp) - ops := []build.TransactionMutator{ - build.SetData(terminatorKey, []byte(tsMillisStr), build.SourceAccount{AddressOrSeed: t.tradingAccount}), + ops := []txnbuild.Operation{ + &txnbuild.ManageData{ + Name: terminatorKey, + Value: []byte(tsMillisStr), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }, } log.Printf("updating delete timestamp to %s\n", tsMillisStr) @@ -127,32 +131,46 @@ func (t *Terminator) run() { func convertToAsset(code string, issuer string) hProtocol.Asset { if code == utils.Native { - return utils.Asset2Asset2(build.NativeAsset()) + return utils.Asset2Asset2(txnbuild.NativeAsset{}) } - return utils.Asset2Asset2(build.CreditAsset(code, issuer)) + return utils.Asset2Asset2(txnbuild.CreditAsset{code, issuer}) } // deleteOffers deletes passed in offers along with the data for the passed in hash func (t *Terminator) deleteOffers(sellOffers []hProtocol.Offer, buyOffers []hProtocol.Offer, botKey model.BotKey, tsMillis int64) { - ops := []build.TransactionMutator{} + ops := []txnbuild.Operation{} ops = append(ops, t.sdex.DeleteAllOffers(sellOffers)...) ops = append(ops, t.sdex.DeleteAllOffers(buyOffers)...) numOffers := len(ops) // delete existing data entries - ops = append(ops, build.ClearData(botKey.FullKey(0), build.SourceAccount{AddressOrSeed: t.tradingAccount})) - ops = append(ops, build.ClearData(botKey.FullKey(1), build.SourceAccount{AddressOrSeed: t.tradingAccount})) + ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(0), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) + ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(1), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) if len(botKey.AssetBaseIssuer) > 0 { - ops = append(ops, build.ClearData(botKey.FullKey(2), build.SourceAccount{AddressOrSeed: t.tradingAccount})) + ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(2), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) } - ops = append(ops, build.ClearData(botKey.FullKey(3), build.SourceAccount{AddressOrSeed: t.tradingAccount})) + ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(3), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) if len(botKey.AssetQuoteIssuer) > 0 { - ops = append(ops, build.ClearData(botKey.FullKey(4), build.SourceAccount{AddressOrSeed: t.tradingAccount})) + ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(4), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) } // update timestamp for terminator tsMillisStr := fmt.Sprintf("%d", tsMillis) - ops = append(ops, build.SetData(terminatorKey, []byte(tsMillisStr), build.SourceAccount{AddressOrSeed: t.tradingAccount})) + ops = append(ops, &txnbuild.ManageData{ + Name: terminatorKey, + Value: []byte(tsMillisStr), + SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + }) log.Printf("deleting %d offers and 5 data entries, updating delete timestamp to %s\n", numOffers, tsMillisStr) if len(ops) > 0 { diff --git a/trader/trader.go b/trader/trader.go index 6414ff98b..17a4f8dbf 100644 --- a/trader/trader.go +++ b/trader/trader.go @@ -8,9 +8,9 @@ import ( "time" "github.com/nikhilsaraf/go-tools/multithreading" - "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" + "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/plugins" @@ -142,7 +142,7 @@ func (t *Trader) deleteAllOffers() { } log.Printf("deleting all offers, num. continuous update cycles with errors (including this one): %d; (deleteCyclesThreshold to be exceeded=%d)\n", t.deleteCycles, t.deleteCyclesThreshold) - dOps := []build.TransactionMutator{} + dOps := []txnbuild.Operation{} dOps = append(dOps, t.sdex.DeleteAllOffers(t.sellingAOffers)...) t.sellingAOffers = []hProtocol.Offer{} dOps = append(dOps, t.sdex.DeleteAllOffers(t.buyingAOffers)...) @@ -192,7 +192,7 @@ func (t *Trader) update() { } // delete excess offers - var pruneOps []build.TransactionMutator + var pruneOps []txnbuild.Operation pruneOps, t.buyingAOffers, t.sellingAOffers = t.strategy.PruneExistingOffers(t.buyingAOffers, t.sellingAOffers) log.Printf("created %d operations to prune excess offers\n", len(pruneOps)) if len(pruneOps) > 0 { From d8b774f5e99e89687b5abfd1d0ac1aafab2cfe57 Mon Sep 17 00:00:00 2001 From: oliha Date: Thu, 25 Jul 2019 16:23:29 -0400 Subject: [PATCH 02/15] use horizonclient error types --- gui/backend/upsert_bot_config.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go index 7360bf998..92b437fa0 100644 --- a/gui/backend/upsert_bot_config.go +++ b/gui/backend/upsert_bot_config.go @@ -8,7 +8,6 @@ import ( "net/http" "strings" - "github.com/stellar/go/clients/horizon" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/go/keypair" "github.com/stellar/go/network" @@ -302,11 +301,11 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, txSuccess, e := client.SubmitTransactionXDR(txn64) if e != nil { - var herr *horizon.Error + var herr *horizonclient.Error switch t := e.(type) { - case *horizon.Error: + case *horizonclient.Error: herr = t - case horizon.Error: + case horizonclient.Error: herr = &t default: return fmt.Errorf("error when submitting change trust transaction for address %s for bot '%s' for assets(%v): %s (%s)\n", address, botName, trustlines, e, txn64) From 4684445aa40d84aba1ea6533c3d2b9ecff85f4e2 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Tue, 27 Aug 2019 17:51:40 +0530 Subject: [PATCH 03/15] fix checkFundAccount which returned an invalid hProtocol.Account structure It was invalid because it was fetch before it existed and therefore was incomplete. --- gui/backend/autogenerate_bot.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gui/backend/autogenerate_bot.go b/gui/backend/autogenerate_bot.go index db4588428..7d5fa821b 100644 --- a/gui/backend/autogenerate_bot.go +++ b/gui/backend/autogenerate_bot.go @@ -186,6 +186,22 @@ func (s *APIServer) checkFundAccount(address string, botName string) (*hProtocol return nil, fmt.Errorf("error funding address %s for bot '%s': %s\n", address, botName, e) } log.Printf("successfully funded account %s for bot '%s': %s\n", address, botName, fundResponse) + + // refetch account to confirm + account, e = s.apiTestNet.AccountDetail(horizonclient.AccountRequest{AccountID: address}) + if e != nil { + var herr *horizonclient.Error + switch t := e.(type) { + case *horizonclient.Error: + herr = t + case horizonclient.Error: + herr = &t + default: + return nil, fmt.Errorf("unexpected error when checking for existence of account %s for bot '%s': %s", address, botName, e) + } + + return nil, fmt.Errorf("horizon error when checking for existence of account %s for bot '%s': %d (%v) -- could this be caused because horizon has not ingested this data yet? (programmer: maybe create hProtocol.Account instance manually instead of fetching)", address, botName, herr.Problem.Status, *herr) + } return &account, nil } From f9ca51039f3cee88c073879a92ab7d9647b5bf43 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 13:44:02 +0530 Subject: [PATCH 04/15] use client registered on APIServer instead of using default horizonclient --- gui/backend/autogenerate_bot.go | 2 +- gui/backend/upsert_bot_config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/backend/autogenerate_bot.go b/gui/backend/autogenerate_bot.go index 7d5fa821b..8c9089fc9 100644 --- a/gui/backend/autogenerate_bot.go +++ b/gui/backend/autogenerate_bot.go @@ -148,7 +148,7 @@ func (s *APIServer) setupAccount(address string, signer string, botName string) return fmt.Errorf("cannot convert trustline transaction to base64 for account %s for bot '%s': %s\n", address, botName, e) } - client := horizonclient.DefaultTestNetClient + client := s.apiTestNet resp, e := client.SubmitTransactionXDR(txn64) if e != nil { return fmt.Errorf("error submitting change trust transaction for address %s for bot '%s': %s\n", address, botName, e) diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go index 1b44dd6e6..57ba2f859 100644 --- a/gui/backend/upsert_bot_config.go +++ b/gui/backend/upsert_bot_config.go @@ -257,7 +257,7 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, // build txn address := kp.Address() accountReq := horizonclient.AccountRequest{AccountID: address} - account, err := horizonclient.DefaultTestNetClient.AccountDetail(accountReq) + account, err := client.AccountDetail(accountReq) if err != nil { return fmt.Errorf("Unable to load account for %s\n: %s", address, err) } From 72f1aa08919b244b6642251a78bcd8ff4176760c Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 13:49:50 +0530 Subject: [PATCH 05/15] fix formatting of txnbuild.CreditAsset struct instantiations --- gui/backend/autogenerate_bot.go | 12 ++++++++---- gui/backend/upsert_bot_config.go | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/gui/backend/autogenerate_bot.go b/gui/backend/autogenerate_bot.go index 8c9089fc9..e7fffca20 100644 --- a/gui/backend/autogenerate_bot.go +++ b/gui/backend/autogenerate_bot.go @@ -105,16 +105,20 @@ func (s *APIServer) setupAccount(address string, signer string, botName string) var txOps []txnbuild.Operation trustOp := txnbuild.ChangeTrust{ - Line: txnbuild.CreditAsset{Code: "COUPON", - Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + Line: txnbuild.CreditAsset{ + Code: "COUPON", + Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", + }, } txOps = append(txOps, &trustOp) paymentOp := txnbuild.Payment{ Destination: address, Amount: "1000.0", - Asset: txnbuild.CreditAsset{Code: "COUPON", - Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + Asset: txnbuild.CreditAsset{ + Code: "COUPON", + Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", + }, SourceAccount: &txnbuild.SimpleAccount{AccountID: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, } txOps = append(txOps, &paymentOp) diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go index 57ba2f859..b39b65795 100644 --- a/gui/backend/upsert_bot_config.go +++ b/gui/backend/upsert_bot_config.go @@ -264,7 +264,6 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, var txOps []txnbuild.Operation for _, a := range trustlines { - trustOp := txnbuild.ChangeTrust{ Line: txnbuild.CreditAsset{Code: a.Code, Issuer: a.Issuer}, } From e007c1bb734b2a82bd2c716fb5261dc85462d8fe Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 14:06:01 +0530 Subject: [PATCH 06/15] distinguish equality methods in utils --- plugins/batchedExchange.go | 13 +------------ support/utils/functions.go | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 7b9c10f1c..5b0dc3e22 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -363,17 +363,6 @@ func convert2Price(number *model.Number) (hProtocol.Price, error) { }, nil } -// to do: @Nikhil this method is similar to utils.assetsEqualXDR. Consider removing one? -func assetsEqual(hAsset hProtocol.Asset, txnAsset txnbuild.Asset) (bool, error) { - if txnAsset.IsNative() { - return hAsset.Type == utils.Native, nil - } else if hAsset.Type == utils.Native { - return false, nil - } - - return txnAsset.GetCode() == hAsset.Code, nil -} - // manageOffer2Order converts a manage offer operation to a model.Order func manageOffer2Order(mob *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, orderConstraints *model.OrderConstraints) (*model.Order, error) { orderAction := model.OrderActionSell @@ -390,7 +379,7 @@ func manageOffer2Order(mob *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, price := model.NumberFromFloat(priceFloat, largePrecision) volume := model.NumberFromFloat(amountFloat/math.Pow(10, 7), largePrecision) - isBuy, e := assetsEqual(quoteAsset, mob.Selling) + isBuy, e := utils.AssetOnlyCodeEquals(quoteAsset, mob.Selling) if e != nil { return nil, fmt.Errorf("could not compare assets, error: %s", e) } diff --git a/support/utils/functions.go b/support/utils/functions.go index 8c3eb90ea..ba317bb06 100644 --- a/support/utils/functions.go +++ b/support/utils/functions.go @@ -270,7 +270,19 @@ func ParseAsset(code string, issuer string) (*hProtocol.Asset, error) { return &asset, nil } -func assetEqualsXDR(hAsset hProtocol.Asset, xAsset txnbuild.Asset) (bool, error) { +// AssetOnlyCodeEquals only checks the type and code of these assets, i.e. insensitive to asset issuer +func AssetOnlyCodeEquals(hAsset hProtocol.Asset, txnAsset txnbuild.Asset) (bool, error) { + if txnAsset.IsNative() { + return hAsset.Type == Native, nil + } else if hAsset.Type == Native { + return false, nil + } + + return txnAsset.GetCode() == hAsset.Code, nil +} + +// assetEqualsExact does an exact comparison of two assets +func assetEqualsExact(hAsset hProtocol.Asset, xAsset txnbuild.Asset) (bool, error) { if xAsset.IsNative() { return hAsset.Type == Native, nil } else if hAsset.Type == Native { @@ -282,11 +294,11 @@ func assetEqualsXDR(hAsset hProtocol.Asset, xAsset txnbuild.Asset) (bool, error) // IsSelling helper method func IsSelling(sdexBase hProtocol.Asset, sdexQuote hProtocol.Asset, selling txnbuild.Asset, buying txnbuild.Asset) (bool, error) { - sellingBase, e := assetEqualsXDR(sdexBase, selling) + sellingBase, e := assetEqualsExact(sdexBase, selling) if e != nil { return false, fmt.Errorf("error comparing sdexBase with selling asset") } - buyingQuote, e := assetEqualsXDR(sdexQuote, buying) + buyingQuote, e := assetEqualsExact(sdexQuote, buying) if e != nil { return false, fmt.Errorf("error comparing sdexQuote with buying asset") } @@ -294,11 +306,11 @@ func IsSelling(sdexBase hProtocol.Asset, sdexQuote hProtocol.Asset, selling txnb return true, nil } - sellingQuote, e := assetEqualsXDR(sdexQuote, selling) + sellingQuote, e := assetEqualsExact(sdexQuote, selling) if e != nil { return false, fmt.Errorf("error comparing sdexQuote with selling asset") } - buyingBase, e := assetEqualsXDR(sdexBase, buying) + buyingBase, e := assetEqualsExact(sdexBase, buying) if e != nil { return false, fmt.Errorf("error comparing sdexBase with buying asset") } From 2c85682c166f78be839dab72324478acbd5dec71 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 15:16:12 +0530 Subject: [PATCH 07/15] panic if we cannot create a delete offer operation avoids threading errors through in this situation where really there should be no reason for an error from the delete offer op, althrough ideally we should thread the error through --- plugins/sdex.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/sdex.go b/plugins/sdex.go index 3c9a8da50..d6c73567c 100644 --- a/plugins/sdex.go +++ b/plugins/sdex.go @@ -197,16 +197,15 @@ func (sdex *SDEX) DeleteAllOffers(offers []hProtocol.Offer) []txnbuild.Operation // DeleteOffer returns the op that needs to be submitted to the network in order to delete the passed in offer func (sdex *SDEX) DeleteOffer(offer hProtocol.Offer) txnbuild.ManageSellOffer { var result txnbuild.ManageSellOffer - var err error + var e error if sdex.SourceAccount == sdex.TradingAccount { - result, err = txnbuild.DeleteOfferOp(offer.ID) + result, e = txnbuild.DeleteOfferOp(offer.ID) } else { - result, err = txnbuild.DeleteOfferOp(offer.ID, &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount}) + result, e = txnbuild.DeleteOfferOp(offer.ID, &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount}) } - if err != nil { - // to do: log or return error - return txnbuild.ManageSellOffer{} + if e != nil { + panic(fmt.Sprintf("unexpected error while creating delete offer op: %s", e)) } return result } From f9a5ffd36227de2e21b3cdb2499452d5a77796d8 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 15:33:48 +0530 Subject: [PATCH 08/15] remove TODO in sdex.go#submitOps and add messages around errors --- plugins/sdex.go | 11 ++++++----- support/utils/functions.go | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/sdex.go b/plugins/sdex.go index d6c73567c..964354fcd 100644 --- a/plugins/sdex.go +++ b/plugins/sdex.go @@ -371,10 +371,11 @@ func (sdex *SDEX) SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash st func (sdex *SDEX) submitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error), asyncMode bool) error { sdex.incrementSeqNum() tx := txnbuild.Transaction{ - //Note: sequence number is decremented here because Transaction.Build auto increments sequence number - // To do: @Nikhil confirm if this works as intended. - SourceAccount: &txnbuild.SimpleAccount{AccountID: sdex.SourceAccount, - Sequence: int64(sdex.seqNum - 1)}, + // sequence number is decremented here because Transaction.Build auto increments sequence number + SourceAccount: &txnbuild.SimpleAccount{ + AccountID: sdex.SourceAccount, + Sequence: int64(sdex.seqNum - 1), + }, Operations: ops, Timebounds: txnbuild.NewInfiniteTimeout(), Network: sdex.Network, @@ -432,7 +433,7 @@ func (sdex *SDEX) sign(tx *txnbuild.Transaction) (string, error) { e = utils.SignWithSeed(tx, sdex.SourceSeed) } if e != nil { - return "", e + return "", fmt.Errorf("error signing transaction: %s", e) } return tx.Base64() diff --git a/support/utils/functions.go b/support/utils/functions.go index ba317bb06..6cff7f60d 100644 --- a/support/utils/functions.go +++ b/support/utils/functions.go @@ -330,16 +330,17 @@ func Shuffle(slice []string) { } } +// SignWithSeed modifies the passed in tx with the signatures of the passed in seeds func SignWithSeed(tx *txnbuild.Transaction, seeds ...string) error { - for _, s := range seeds { + for i, s := range seeds { kp, e := keypair.Parse(s) if e != nil { - return e + return fmt.Errorf("cannot parse seed into keypair at index %d: %s", i, e) } e = tx.Sign(kp.(*keypair.Full)) if e != nil { - return e + return fmt.Errorf("cannot sign tx with keypair at index %d (pubKey: %s): %s", i, kp.Address(), e) } } From ce1c79f6b6cf749e0db8803f67b2b2d028e6eb5f Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 17:03:47 +0530 Subject: [PATCH 09/15] fix float64 vs. stoops value string in manageSellOffer.Amount --- plugins/batchedExchange.go | 11 +++-------- plugins/makerModeFilter.go | 13 +++---------- plugins/orderConstraintsFilter.go | 23 +++++++++-------------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 5b0dc3e22..e91f047bd 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -374,11 +374,11 @@ func manageOffer2Order(mob *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, amountFloat, e := strconv.ParseFloat(mob.Amount, 64) if e != nil { - return nil, fmt.Errorf("could not convert amount to float: %s", e) + return nil, fmt.Errorf("could not convert amount (%s) to float: %s", mob.Amount, e) } price := model.NumberFromFloat(priceFloat, largePrecision) - volume := model.NumberFromFloat(amountFloat/math.Pow(10, 7), largePrecision) + volume := model.NumberFromFloat(amountFloat, largePrecision) isBuy, e := utils.AssetOnlyCodeEquals(quoteAsset, mob.Selling) if e != nil { return nil, fmt.Errorf("could not compare assets, error: %s", e) @@ -464,12 +464,7 @@ func op2CommandsHack( return nil, fmt.Errorf("error converting from manageOffer op to Order: %s", e) } - amountFloat, e := strconv.ParseFloat(manageOffer.Amount, 64) - if e != nil { - return nil, fmt.Errorf("could not convert amount to float: %s", e) - } - - if amountFloat == 0 { + if manageOffer.Amount == "0" { // cancel // fetch real orderID here (hoops we have to jump through because of the hacked approach to using centralized exchanges) var orderID string diff --git a/plugins/makerModeFilter.go b/plugins/makerModeFilter.go index e55428c32..5d22ad0c8 100644 --- a/plugins/makerModeFilter.go +++ b/plugins/makerModeFilter.go @@ -3,7 +3,6 @@ package plugins import ( "fmt" "log" - "math" "strconv" hProtocol "github.com/stellar/go/protocols/horizon" @@ -176,14 +175,8 @@ func (f *makerModeFilter) transformOfferMakerMode( topAskPrice *model.Number, op *txnbuild.ManageSellOffer, ) (*txnbuild.ManageSellOffer, bool, error) { - //represent amount as float - amountFloat, e := strconv.ParseFloat(op.Amount, 64) - if e != nil { - return nil, false, fmt.Errorf("could not convert amount to float: %s", e) - } - // delete operations should never be dropped - if amountFloat == 0 { + if op.Amount == "0" { return op, true, nil } @@ -224,11 +217,11 @@ func (f *makerModeFilter) transformOfferMakerMode( if op.OfferID == 0 { // new offers can be dropped return nil, false, nil - } else if amountFloat != 0 { + } else if op.Amount != "0" { // modify offers should be converted to delete offers opCopy := *op opCopy.Amount = "0" return &opCopy, false, nil } - return nil, keep, fmt.Errorf("unable to transform manageOffer operation: offerID=%d, amount=%.7f, price=%.7f", op.OfferID, amountFloat/math.Pow(10, 7), sellPrice) + return nil, keep, fmt.Errorf("unable to transform manageOffer operation: offerID=%d, amount=%s, price=%.7f", op.OfferID, op.Amount, sellPrice) } diff --git a/plugins/orderConstraintsFilter.go b/plugins/orderConstraintsFilter.go index 7d3c1805a..13c6754c7 100644 --- a/plugins/orderConstraintsFilter.go +++ b/plugins/orderConstraintsFilter.go @@ -3,7 +3,6 @@ package plugins import ( "fmt" "log" - "math" "strconv" hProtocol "github.com/stellar/go/protocols/horizon" @@ -59,11 +58,6 @@ func (f *orderConstraintsFilter) Apply( keep = true } - amountFloat, e := strconv.ParseFloat(opPtr.Amount, 64) - if e != nil { - return nil, fmt.Errorf("could not convert amount to float: %s", e) - } - if keep { filteredOps = append(filteredOps, opPtr) numKeep++ @@ -72,13 +66,13 @@ func (f *orderConstraintsFilter) Apply( // figure out how to convert the offer to a dropped state if opPtr.OfferID == 0 { // new offers can be dropped, so don't add to filteredOps - } else if amountFloat != 0 { + } else if opPtr.Amount != "0" { // modify offers should be converted to delete offers opCopy := *opPtr opCopy.Amount = "0" filteredOps = append(filteredOps, &opCopy) } else { - return nil, fmt.Errorf("unable to drop manageOffer operation (probably a delete op that should not have reached here): offerID=%d, amountRaw=%.8f", opPtr.OfferID, amountFloat) + return nil, fmt.Errorf("unable to drop manageOffer operation (probably a delete op that should not have reached here): offerID=%d, amountRaw=%s", opPtr.OfferID, opPtr.Amount) } } } @@ -89,12 +83,13 @@ func (f *orderConstraintsFilter) Apply( func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) (bool, error) { // delete operations should never be dropped + if op.Amount == "0" { + return true, nil + } + amountFloat, e := strconv.ParseFloat(op.Amount, 64) if e != nil { - return false, fmt.Errorf("could not convert amount to float: %s", e) - } - if amountFloat == 0 { - return true, nil + return false, fmt.Errorf("could not convert amount (%s) to float: %s", op.Amount, e) } isSell, e := utils.IsSelling(f.baseAsset, f.quoteAsset, op.Selling, op.Buying) @@ -108,7 +103,7 @@ func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) ( } if isSell { - baseAmount := amountFloat / math.Pow(10, 7) + baseAmount := amountFloat quoteAmount := baseAmount * sellPrice if baseAmount < f.oc.MinBaseVolume.AsFloat() { log.Printf("orderConstraintsFilter: selling, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString()) @@ -123,7 +118,7 @@ func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) ( } // buying - quoteAmount := amountFloat / math.Pow(10, 7) + quoteAmount := amountFloat baseAmount := quoteAmount * sellPrice if baseAmount < f.oc.MinBaseVolume.AsFloat() { log.Printf("orderConstraintsFilter: buying, keep = (baseAmount) %.8f < %s (MinBaseVolume): keep = false\n", baseAmount, f.oc.MinBaseVolume.AsString()) From 6c487dcdcd5e8799aed0c9c9dc852b416dd8d72c Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 17:12:39 +0530 Subject: [PATCH 10/15] update log line from build.ManageOfferBuilder -> txnbuild.ManageSellOffer --- plugins/batchedExchange.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index e91f047bd..9c782c729 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -440,7 +440,7 @@ func Ops2CommandsHack( case *txnbuild.ManageSellOffer: c, e := op2CommandsHack(manageOffer, baseAsset, quoteAsset, offerID2OrderID, orderConstraints) if e != nil { - return nil, fmt.Errorf("unable to convert *build.ManageOfferBuilder to a Command: %s", e) + return nil, fmt.Errorf("unable to convert *txnbuild.ManageSellOffer to a Command: %s", e) } commands = append(commands, c...) default: From 13797a40e91f13dede014838c31eef1ff19a3d72 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 17:16:32 +0530 Subject: [PATCH 11/15] add string price in error message when attempting conversion to float --- plugins/batchedExchange.go | 2 +- plugins/makerModeFilter.go | 2 +- plugins/orderConstraintsFilter.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 9c782c729..2af7fe220 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -369,7 +369,7 @@ func manageOffer2Order(mob *txnbuild.ManageSellOffer, baseAsset hProtocol.Asset, priceFloat, e := strconv.ParseFloat(mob.Price, 64) if e != nil { - return nil, fmt.Errorf("could not convert price to float: %s", e) + return nil, fmt.Errorf("could not convert price (%s) to float: %s", mob.Price, e) } amountFloat, e := strconv.ParseFloat(mob.Amount, 64) diff --git a/plugins/makerModeFilter.go b/plugins/makerModeFilter.go index 5d22ad0c8..188f8728e 100644 --- a/plugins/makerModeFilter.go +++ b/plugins/makerModeFilter.go @@ -187,7 +187,7 @@ func (f *makerModeFilter) transformOfferMakerMode( sellPrice, e := strconv.ParseFloat(op.Price, 64) if e != nil { - return nil, false, fmt.Errorf("could not convert price to float: %s", e) + return nil, false, fmt.Errorf("could not convert price (%s) to float: %s", op.Price, e) } var keep bool diff --git a/plugins/orderConstraintsFilter.go b/plugins/orderConstraintsFilter.go index 13c6754c7..94ddd1de2 100644 --- a/plugins/orderConstraintsFilter.go +++ b/plugins/orderConstraintsFilter.go @@ -99,7 +99,7 @@ func (f *orderConstraintsFilter) shouldKeepOffer(op *txnbuild.ManageSellOffer) ( sellPrice, e := strconv.ParseFloat(op.Price, 64) if e != nil { - return false, fmt.Errorf("could not convert price to float: %s", e) + return false, fmt.Errorf("could not convert price (%s) to float: %s", op.Price, e) } if isSell { From b23787a2f1f3ad50c2f6f2788fbfe187d46bf42b Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 17:54:39 +0530 Subject: [PATCH 12/15] convert horizon.Asset -> hProtocol.Asset --- gui/backend/get_bot_info.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gui/backend/get_bot_info.go b/gui/backend/get_bot_info.go index 91331a5c9..dfc3ac731 100644 --- a/gui/backend/get_bot_info.go +++ b/gui/backend/get_bot_info.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "github.com/stellar/go/clients/horizon" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/config" @@ -215,7 +214,7 @@ func getNativeBalance(account hProtocol.Account) (float64, error) { return balance, nil } -func getCreditBalance(account hProtocol.Account, asset horizon.Asset) (float64, error) { +func getCreditBalance(account hProtocol.Account, asset hProtocol.Asset) (float64, error) { balanceString := account.GetCreditBalance(asset.Code, asset.Issuer) balance, e := strconv.ParseFloat(balanceString, 64) if e != nil { From 13db5384d0c5e18e45d207b9c582f669a27ac303 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 17:56:42 +0530 Subject: [PATCH 13/15] remove last references to horizon.Client --- gui/backend/api_server.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/gui/backend/api_server.go b/gui/backend/api_server.go index 96077a11c..f3d20e56e 100644 --- a/gui/backend/api_server.go +++ b/gui/backend/api_server.go @@ -10,7 +10,6 @@ import ( "path/filepath" "strings" - "github.com/stellar/go/clients/horizon" "github.com/stellar/go/clients/horizonclient" "github.com/stellar/kelp/support/kelpos" ) @@ -27,8 +26,6 @@ type APIServer struct { ccxtRestUrl string apiTestNet *horizonclient.Client apiPubNet *horizonclient.Client - apiTestNetOld *horizon.Client - apiPubNetOld *horizon.Client cachedOptionsMetadata metadata } @@ -56,14 +53,6 @@ func MakeAPIServer(kos *kelpos.KelpOS, horizonTestnetURI string, horizonPubnetUR HorizonURL: horizonPubnetURI, HTTP: http.DefaultClient, } - apiTestNetOld := &horizon.Client{ - URL: horizonTestnetURI, - HTTP: http.DefaultClient, - } - apiPubNetOld := &horizon.Client{ - URL: horizonPubnetURI, - HTTP: http.DefaultClient, - } optionsMetadata, e := loadOptionsMetadata() if e != nil { @@ -81,8 +70,6 @@ func MakeAPIServer(kos *kelpos.KelpOS, horizonTestnetURI string, horizonPubnetUR ccxtRestUrl: ccxtRestUrl, apiTestNet: apiTestNet, apiPubNet: apiPubNet, - apiTestNetOld: apiTestNetOld, - apiPubNetOld: apiPubNetOld, cachedOptionsMetadata: optionsMetadata, }, nil } From 4b3734ba29522ca7875e10c60f3015bcf38e5148 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Fri, 30 Aug 2019 18:00:30 +0530 Subject: [PATCH 14/15] remove build and clients/horizon package from glide yaml and lock file --- glide.lock | 7 ++----- glide.yaml | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/glide.lock b/glide.lock index 6e40e0b65..8ebc07fae 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 6221ecb513f011696bf06ccf89b7f15cd77ac17a5b075beb8562a74ee10e1f34 -updated: 2019-07-19T12:33:12.198828562-07:00 +hash: 93f84071fccdfc0c10e17f1808daa7461f29f9bf3bca6dec05b4fbb9068ba487 +updated: 2019-08-30T04:28:19.867973525-07:00 imports: - name: cloud.google.com/go version: 24f9f82cf8c5ed3c0303f34f76876365ce742aad @@ -106,8 +106,6 @@ imports: version: a599ed95b928a7bdcee21cee4999efd05e43c2df subpackages: - amount - - build - - clients/horizon - clients/horizonclient - crc16 - hash @@ -119,7 +117,6 @@ imports: - protocols/horizon/effects - protocols/horizon/operations - strkey - - support/app - support/config - support/errors - support/log diff --git a/glide.yaml b/glide.yaml index b3d1f114a..95508bf0c 100644 --- a/glide.yaml +++ b/glide.yaml @@ -11,8 +11,6 @@ import: - package: github.com/stellar/go version: a599ed95b928a7bdcee21cee4999efd05e43c2df subpackages: - - build - - clients/horizon - clients/horizonclient - support/config - support/errors From f4b90251dd9dd283b2435b544c2aece94871558a Mon Sep 17 00:00:00 2001 From: Nikhil Saraf <1028334+nikhilsaraf@users.noreply.github.com> Date: Tue, 3 Sep 2019 13:47:33 +0530 Subject: [PATCH 15/15] use build package in API interfaces + undo glide removals --- api/exchange.go | 88 ++++++++++++++++++++++++++++++++++- api/strategy.go | 10 ++-- cmd/trade.go | 2 +- glide.lock | 5 +- glide.yaml | 1 + plugins/batchedExchange.go | 7 ++- plugins/composeStrategy.go | 8 ++-- plugins/deleteSideStrategy.go | 9 ++-- plugins/mirrorStrategy.go | 9 ++-- plugins/sdex.go | 9 ++-- plugins/sellSideStrategy.go | 10 ++-- terminator/terminator.go | 5 +- trader/trader.go | 10 ++-- 13 files changed, 136 insertions(+), 37 deletions(-) diff --git a/api/exchange.go b/api/exchange.go index be753c1de..8354438dd 100644 --- a/api/exchange.go +++ b/api/exchange.go @@ -2,9 +2,12 @@ package api import ( "fmt" + "math" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" + "github.com/stellar/go/xdr" "github.com/stellar/kelp/model" ) @@ -222,11 +225,92 @@ type Balance struct { // ExchangeShim is the interface we use as a generic API for all crypto exchanges type ExchangeShim interface { - SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error - SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error // forced synchronous version of SubmitOps + SubmitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error + SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error // forced synchronous version of SubmitOps GetBalanceHack(asset hProtocol.Asset) (*Balance, error) LoadOffersHack() ([]hProtocol.Offer, error) Constrainable OrderbookFetcher FillTrackable } + +// ConvertOperation2TM is a temporary adapter to support transitioning from the old Go SDK to the new SDK without having to bump the major version +func ConvertOperation2TM(ops []txnbuild.Operation) []build.TransactionMutator { + muts := []build.TransactionMutator{} + for _, o := range ops { + var mob build.ManageOfferBuilder + if mso, ok := o.(*txnbuild.ManageSellOffer); ok { + mob = build.ManageOffer( + false, + build.Amount(mso.Amount), + build.Rate{ + Selling: build.Asset{Code: mso.Selling.GetCode(), Issuer: mso.Selling.GetIssuer(), Native: mso.Selling.IsNative()}, + Buying: build.Asset{Code: mso.Buying.GetCode(), Issuer: mso.Buying.GetIssuer(), Native: mso.Buying.IsNative()}, + Price: build.Price(mso.Price), + }, + build.OfferID(mso.OfferID), + ) + if mso.SourceAccount != nil { + mob.Mutate(build.SourceAccount{AddressOrSeed: mso.SourceAccount.GetAccountID()}) + } + } else { + panic(fmt.Sprintf("could not convert txnbuild.Operation to build.TransactionMutator: %v\n", o)) + } + muts = append(muts, mob) + } + return muts +} + +// ConvertTM2Operation is a temporary adapter to support transitioning from the old Go SDK to the new SDK without having to bump the major version +func ConvertTM2Operation(muts []build.TransactionMutator) []txnbuild.Operation { + ops := []txnbuild.Operation{} + for _, m := range muts { + var mso *txnbuild.ManageSellOffer + if mob, ok := m.(build.ManageOfferBuilder); ok { + mso = convertMOB2MSO(mob) + } else if mob, ok := m.(*build.ManageOfferBuilder); ok { + mso = convertMOB2MSO(*mob) + } else { + panic(fmt.Sprintf("could not convert build.TransactionMutator to txnbuild.Operation: %v (type=%T)\n", m, m)) + } + ops = append(ops, mso) + } + return ops +} + +func convertMOB2MSO(mob build.ManageOfferBuilder) *txnbuild.ManageSellOffer { + mso := &txnbuild.ManageSellOffer{ + Amount: fmt.Sprintf("%.7f", float64(mob.MO.Amount)/math.Pow(10, 7)), + OfferID: int64(mob.MO.OfferId), + Price: fmt.Sprintf("%.7f", float64(mob.MO.Price.N)/float64(mob.MO.Price.D)), + } + if mob.O.SourceAccount != nil { + mso.SourceAccount = &txnbuild.SimpleAccount{ + AccountID: mob.O.SourceAccount.Address(), + } + } + + if mob.MO.Buying.Type == xdr.AssetTypeAssetTypeNative { + mso.Buying = txnbuild.NativeAsset{} + } else { + var tipe, code, issuer string + mob.MO.Buying.MustExtract(&tipe, &code, &issuer) + mso.Buying = txnbuild.CreditAsset{ + Code: code, + Issuer: issuer, + } + } + + if mob.MO.Selling.Type == xdr.AssetTypeAssetTypeNative { + mso.Selling = txnbuild.NativeAsset{} + } else { + var tipe, code, issuer string + mob.MO.Selling.MustExtract(&tipe, &code, &issuer) + mso.Selling = txnbuild.CreditAsset{ + Code: code, + Issuer: issuer, + } + } + + return mso +} diff --git a/api/strategy.go b/api/strategy.go index 226fc46fe..7a0de795f 100644 --- a/api/strategy.go +++ b/api/strategy.go @@ -1,25 +1,25 @@ package api import ( + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" - "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/model" ) // Strategy represents some logic for a bot to follow while doing market making type Strategy interface { - PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) + PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) PreUpdate(maxAssetA float64, maxAssetB float64, trustA float64, trustB float64) error - UpdateWithOps(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, error) + UpdateWithOps(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, error) PostUpdate() error GetFillHandlers() ([]FillHandler, error) } // SideStrategy represents a strategy on a single side of the orderbook type SideStrategy interface { - PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) + PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) PreUpdate(maxAssetA float64, maxAssetB float64, trustA float64, trustB float64) error - UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) + UpdateWithOps(offers []hProtocol.Offer) (ops []build.TransactionMutator, newTopOffer *model.Number, e error) PostUpdate() error GetFillHandlers() ([]FillHandler, error) } diff --git a/cmd/trade.go b/cmd/trade.go index b34118ed5..d2e7969de 100644 --- a/cmd/trade.go +++ b/cmd/trade.go @@ -697,7 +697,7 @@ func deleteAllOffersAndExit( l.Infof("created %d operations to delete offers\n", len(dOps)) if len(dOps) > 0 { - e := exchangeShim.SubmitOpsSynch(dOps, func(hash string, e error) { + e := exchangeShim.SubmitOpsSynch(api.ConvertOperation2TM(dOps), func(hash string, e error) { if e != nil { logger.Fatal(l, e) return diff --git a/glide.lock b/glide.lock index 8ebc07fae..f080d8e24 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 93f84071fccdfc0c10e17f1808daa7461f29f9bf3bca6dec05b4fbb9068ba487 -updated: 2019-08-30T04:28:19.867973525-07:00 +hash: fea1924a14461af263f5435ea1fc0038870ad2b82b4fe6dec3e679cfea5b5bc9 +updated: 2019-08-30T05:39:34.749230033-07:00 imports: - name: cloud.google.com/go version: 24f9f82cf8c5ed3c0303f34f76876365ce742aad @@ -106,6 +106,7 @@ imports: version: a599ed95b928a7bdcee21cee4999efd05e43c2df subpackages: - amount + - build - clients/horizonclient - crc16 - hash diff --git a/glide.yaml b/glide.yaml index 95508bf0c..a191792b2 100644 --- a/glide.yaml +++ b/glide.yaml @@ -11,6 +11,7 @@ import: - package: github.com/stellar/go version: a599ed95b928a7bdcee21cee4999efd05e43c2df subpackages: + - build - clients/horizonclient - support/config - support/errors diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 2af7fe220..001835a0c 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -10,6 +10,7 @@ import ( "math/rand" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" @@ -174,12 +175,14 @@ func (b BatchedExchange) GetLatestTradeCursor() (interface{}, error) { } // SubmitOpsSynch is the forced synchronous version of SubmitOps below (same for batchedExchange) -func (b BatchedExchange) SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { +func (b BatchedExchange) SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { return b.SubmitOps(ops, asyncCallback) } // SubmitOps performs any finalization or submission step needed by the exchange -func (b BatchedExchange) SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { +func (b BatchedExchange) SubmitOps(opsOld []build.TransactionMutator, asyncCallback func(hash string, e error)) error { + ops := api.ConvertTM2Operation(opsOld) + var e error b.commands, e = b.Ops2Commands(ops, b.baseAsset, b.quoteAsset) if e != nil { diff --git a/plugins/composeStrategy.go b/plugins/composeStrategy.go index 4eff925fd..359f3e1f4 100644 --- a/plugins/composeStrategy.go +++ b/plugins/composeStrategy.go @@ -6,9 +6,9 @@ import ( "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/errors" - "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/support/utils" ) @@ -39,7 +39,7 @@ func makeComposeStrategy( } // PruneExistingOffers impl -func (s *composeStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) { +func (s *composeStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) { pruneOps1, newBuyingAOffers := s.buyStrat.PruneExistingOffers(buyingAOffers) pruneOps2, newSellingAOffers := s.sellStrat.PruneExistingOffers(sellingAOffers) pruneOps1 = append(pruneOps1, pruneOps2...) @@ -71,7 +71,7 @@ func (s *composeStrategy) PreUpdate(maxAssetBase float64, maxAssetQuote float64, func (s *composeStrategy) UpdateWithOps( buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer, -) ([]txnbuild.Operation, error) { +) ([]build.TransactionMutator, error) { // buy side, flip newTopBuyPrice because it will be inverted from this parent strategy's context of base/quote buyOps, newTopBuyPriceInverted, e1 := s.buyStrat.UpdateWithOps(buyingAOffers) newTopBuyPrice := model.InvertNumber(newTopBuyPriceInverted) @@ -79,7 +79,7 @@ func (s *composeStrategy) UpdateWithOps( sellOps, _, e2 := s.sellStrat.UpdateWithOps(sellingAOffers) // check for errors - ops := []txnbuild.Operation{} + ops := []build.TransactionMutator{} if e1 != nil && e2 != nil { return ops, fmt.Errorf("errors on both sides: buying (= %s) and selling (= %s)", e1, e2) } else if e1 != nil { diff --git a/plugins/deleteSideStrategy.go b/plugins/deleteSideStrategy.go index 3d07d4b66..350419e91 100644 --- a/plugins/deleteSideStrategy.go +++ b/plugins/deleteSideStrategy.go @@ -3,6 +3,7 @@ package plugins import ( "log" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" @@ -33,14 +34,14 @@ func makeDeleteSideStrategy( } // PruneExistingOffers impl -func (s *deleteSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) { +func (s *deleteSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) { log.Printf("deleteSideStrategy: deleting %d offers\n", len(offers)) pruneOps := []txnbuild.Operation{} for i := 0; i < len(offers); i++ { pOp := s.sdex.DeleteOffer(offers[i]) pruneOps = append(pruneOps, &pOp) } - return pruneOps, []hProtocol.Offer{} + return api.ConvertOperation2TM(pruneOps), []hProtocol.Offer{} } // PreUpdate impl @@ -49,8 +50,8 @@ func (s *deleteSideStrategy) PreUpdate(maxAssetBase float64, maxAssetQuote float } // UpdateWithOps impl -func (s *deleteSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) { - return []txnbuild.Operation{}, nil, nil +func (s *deleteSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []build.TransactionMutator, newTopOffer *model.Number, e error) { + return []build.TransactionMutator{}, nil, nil } // PostUpdate impl diff --git a/plugins/mirrorStrategy.go b/plugins/mirrorStrategy.go index fe58437dc..cd05af6c4 100644 --- a/plugins/mirrorStrategy.go +++ b/plugins/mirrorStrategy.go @@ -5,6 +5,7 @@ import ( "log" "sync" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" @@ -192,8 +193,8 @@ func makeMirrorStrategy(sdex *SDEX, ieif *IEIF, pair *model.TradingPair, baseAss } // PruneExistingOffers deletes any extra offers -func (s *mirrorStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer, []hProtocol.Offer) { - return []txnbuild.Operation{}, buyingAOffers, sellingAOffers +func (s *mirrorStrategy) PruneExistingOffers(buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer, []hProtocol.Offer) { + return []build.TransactionMutator{}, buyingAOffers, sellingAOffers } // PreUpdate changes the strategy's state in prepration for the update @@ -230,7 +231,7 @@ func (s *mirrorStrategy) recordBalances() error { func (s *mirrorStrategy) UpdateWithOps( buyingAOffers []hProtocol.Offer, sellingAOffers []hProtocol.Offer, -) ([]txnbuild.Operation, error) { +) ([]build.TransactionMutator, error) { ob, e := s.exchange.GetOrderBook(s.backingPair, s.orderbookDepth) if e != nil { return nil, e @@ -295,7 +296,7 @@ func (s *mirrorStrategy) UpdateWithOps( ops = append(ops, sellOps...) } - return ops, nil + return api.ConvertOperation2TM(ops), nil } func (s *mirrorStrategy) updateLevels( diff --git a/plugins/sdex.go b/plugins/sdex.go index 964354fcd..980661a2a 100644 --- a/plugins/sdex.go +++ b/plugins/sdex.go @@ -12,6 +12,7 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" "github.com/pkg/errors" + "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" @@ -358,17 +359,19 @@ func (sdex *SDEX) createModifySellOffer(offer *hProtocol.Offer, selling hProtoco } // SubmitOpsSynch is the forced synchronous version of SubmitOps below -func (sdex *SDEX) SubmitOpsSynch(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { +func (sdex *SDEX) SubmitOpsSynch(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { return sdex.submitOps(ops, asyncCallback, false) } // SubmitOps submits the passed in operations to the network asynchronously in a single transaction -func (sdex *SDEX) SubmitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error)) error { +func (sdex *SDEX) SubmitOps(ops []build.TransactionMutator, asyncCallback func(hash string, e error)) error { return sdex.submitOps(ops, asyncCallback, true) } // submitOps submits the passed in operations to the network in a single transaction. Asynchronous or not based on flag. -func (sdex *SDEX) submitOps(ops []txnbuild.Operation, asyncCallback func(hash string, e error), asyncMode bool) error { +func (sdex *SDEX) submitOps(opsOld []build.TransactionMutator, asyncCallback func(hash string, e error), asyncMode bool) error { + ops := api.ConvertTM2Operation(opsOld) + sdex.incrementSeqNum() tx := txnbuild.Transaction{ // sequence number is decremented here because Transaction.Build auto increments sequence number diff --git a/plugins/sellSideStrategy.go b/plugins/sellSideStrategy.go index 4c864f1d9..84a737157 100644 --- a/plugins/sellSideStrategy.go +++ b/plugins/sellSideStrategy.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/stellar/go/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" @@ -67,7 +68,7 @@ func makeSellSideStrategy( } // PruneExistingOffers impl -func (s *sellSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]txnbuild.Operation, []hProtocol.Offer) { +func (s *sellSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]build.TransactionMutator, []hProtocol.Offer) { // figure out which offers we want to prune shouldPrune := computeOffersToPrune(offers, s.desiredLevels) @@ -91,7 +92,7 @@ func (s *sellSideStrategy) PruneExistingOffers(offers []hProtocol.Offer) ([]txnb // base and quote here refers to the bot's base and quote, not the base and quote of the sellSideStrategy log.Printf("offer | %s | level=%d | curPriceQuote=%.8f | curAmtBase=%.8f | pruning=%v\n", s.action, i+1, curPrice, curAmount, isPruning) } - return pruneOps, updatedOffers + return api.ConvertOperation2TM(pruneOps), updatedOffers } // computeOffersToPrune returns a list of bools representing whether we should prune the offer at that position or not @@ -259,7 +260,8 @@ func (s *sellSideStrategy) createPrecedingOffers( } // UpdateWithOps impl -func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []txnbuild.Operation, newTopOffer *model.Number, e error) { +func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (opsOld []build.TransactionMutator, newTopOffer *model.Number, e error) { + var ops []txnbuild.Operation deleteOps := []txnbuild.Operation{} // first we want to re-create any offers that precede our existing offers and are additions to the existing offers that we have @@ -325,7 +327,7 @@ func (s *sellSideStrategy) UpdateWithOps(offers []hProtocol.Offer) (ops []txnbui // prepend deleteOps because we want to delete offers first so we "free" up our liabilities capacity to place the new/modified offers ops = append(deleteOps, ops...) - return ops, newTopOffer, nil + return api.ConvertOperation2TM(ops), newTopOffer, nil } // PostUpdate impl diff --git a/terminator/terminator.go b/terminator/terminator.go index ddacccc9d..ecf2efe46 100644 --- a/terminator/terminator.go +++ b/terminator/terminator.go @@ -10,6 +10,7 @@ import ( "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" + "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" "github.com/stellar/kelp/plugins" "github.com/stellar/kelp/support/utils" @@ -105,7 +106,7 @@ func (t *Terminator) run() { } log.Printf("updating delete timestamp to %s\n", tsMillisStr) - e = t.sdex.SubmitOps(ops, nil) + e = t.sdex.SubmitOps(api.ConvertOperation2TM(ops), nil) if e != nil { log.Println(e) } @@ -174,7 +175,7 @@ func (t *Terminator) deleteOffers(sellOffers []hProtocol.Offer, buyOffers []hPro log.Printf("deleting %d offers and 5 data entries, updating delete timestamp to %s\n", numOffers, tsMillisStr) if len(ops) > 0 { - e := t.sdex.SubmitOps(ops, nil) + e := t.sdex.SubmitOps(api.ConvertOperation2TM(ops), nil) if e != nil { log.Println(e) return diff --git a/trader/trader.go b/trader/trader.go index 17a4f8dbf..2abcfe1ab 100644 --- a/trader/trader.go +++ b/trader/trader.go @@ -8,6 +8,7 @@ import ( "time" "github.com/nikhilsaraf/go-tools/multithreading" + "github.com/stellar/go/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" @@ -150,7 +151,7 @@ func (t *Trader) deleteAllOffers() { log.Printf("created %d operations to delete offers\n", len(dOps)) if len(dOps) > 0 { - e := t.exchangeShim.SubmitOps(dOps, nil) + e := t.exchangeShim.SubmitOps(api.ConvertOperation2TM(dOps), nil) if e != nil { log.Println(e) return @@ -192,7 +193,7 @@ func (t *Trader) update() { } // delete excess offers - var pruneOps []txnbuild.Operation + var pruneOps []build.TransactionMutator pruneOps, t.buyingAOffers, t.sellingAOffers = t.strategy.PruneExistingOffers(t.buyingAOffers, t.sellingAOffers) log.Printf("created %d operations to prune excess offers\n", len(pruneOps)) if len(pruneOps) > 0 { @@ -217,7 +218,7 @@ func (t *Trader) update() { return } - ops, e := t.strategy.UpdateWithOps(t.buyingAOffers, t.sellingAOffers) + opsOld, e := t.strategy.UpdateWithOps(t.buyingAOffers, t.sellingAOffers) log.Printf("liabilities at the end of a call to UpdateWithOps\n") t.sdex.IEIF().LogAllLiabilities(t.assetBase, t.assetQuote) if e != nil { @@ -228,6 +229,7 @@ func (t *Trader) update() { return } + ops := api.ConvertTM2Operation(opsOld) for i, filter := range t.submitFilters { ops, e = filter.Apply(ops, t.sellingAOffers, t.buyingAOffers) if e != nil { @@ -239,7 +241,7 @@ func (t *Trader) update() { log.Printf("created %d operations to update existing offers\n", len(ops)) if len(ops) > 0 { - e = t.exchangeShim.SubmitOps(ops, nil) + e = t.exchangeShim.SubmitOps(api.ConvertOperation2TM(ops), nil) if e != nil { log.Println(e) t.deleteAllOffers()