Skip to content
This repository was archived by the owner on Feb 1, 2024. It is now read-only.

Commit c18c97f

Browse files
polihanikhilsaraf
authored andcommitted
Use txnbuild (#205), closes #269
* use txnbuild * use horizonclient error types * fix checkFundAccount which returned an invalid hProtocol.Account structure It was invalid because it was fetch before it existed and therefore was incomplete. * use client registered on APIServer instead of using default horizonclient * fix formatting of txnbuild.CreditAsset struct instantiations * distinguish equality methods in utils * 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 * remove TODO in sdex.go#submitOps and add messages around errors * fix float64 vs. stoops value string in manageSellOffer.Amount * update log line from build.ManageOfferBuilder -> txnbuild.ManageSellOffer * add string price in error message when attempting conversion to float * convert horizon.Asset -> hProtocol.Asset * remove last references to horizon.Client * remove build and clients/horizon package from glide yaml and lock file * use build package in API interfaces + undo glide removals
1 parent 6e0fc57 commit c18c97f

21 files changed

Lines changed: 449 additions & 281 deletions

api/exchange.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package api
22

33
import (
44
"fmt"
5+
"math"
56

67
"github.com/stellar/go/build"
78
hProtocol "github.com/stellar/go/protocols/horizon"
9+
"github.com/stellar/go/txnbuild"
10+
"github.com/stellar/go/xdr"
811
"github.com/stellar/kelp/model"
912
)
1013

@@ -230,3 +233,84 @@ type ExchangeShim interface {
230233
OrderbookFetcher
231234
FillTrackable
232235
}
236+
237+
// ConvertOperation2TM is a temporary adapter to support transitioning from the old Go SDK to the new SDK without having to bump the major version
238+
func ConvertOperation2TM(ops []txnbuild.Operation) []build.TransactionMutator {
239+
muts := []build.TransactionMutator{}
240+
for _, o := range ops {
241+
var mob build.ManageOfferBuilder
242+
if mso, ok := o.(*txnbuild.ManageSellOffer); ok {
243+
mob = build.ManageOffer(
244+
false,
245+
build.Amount(mso.Amount),
246+
build.Rate{
247+
Selling: build.Asset{Code: mso.Selling.GetCode(), Issuer: mso.Selling.GetIssuer(), Native: mso.Selling.IsNative()},
248+
Buying: build.Asset{Code: mso.Buying.GetCode(), Issuer: mso.Buying.GetIssuer(), Native: mso.Buying.IsNative()},
249+
Price: build.Price(mso.Price),
250+
},
251+
build.OfferID(mso.OfferID),
252+
)
253+
if mso.SourceAccount != nil {
254+
mob.Mutate(build.SourceAccount{AddressOrSeed: mso.SourceAccount.GetAccountID()})
255+
}
256+
} else {
257+
panic(fmt.Sprintf("could not convert txnbuild.Operation to build.TransactionMutator: %v\n", o))
258+
}
259+
muts = append(muts, mob)
260+
}
261+
return muts
262+
}
263+
264+
// ConvertTM2Operation is a temporary adapter to support transitioning from the old Go SDK to the new SDK without having to bump the major version
265+
func ConvertTM2Operation(muts []build.TransactionMutator) []txnbuild.Operation {
266+
ops := []txnbuild.Operation{}
267+
for _, m := range muts {
268+
var mso *txnbuild.ManageSellOffer
269+
if mob, ok := m.(build.ManageOfferBuilder); ok {
270+
mso = convertMOB2MSO(mob)
271+
} else if mob, ok := m.(*build.ManageOfferBuilder); ok {
272+
mso = convertMOB2MSO(*mob)
273+
} else {
274+
panic(fmt.Sprintf("could not convert build.TransactionMutator to txnbuild.Operation: %v (type=%T)\n", m, m))
275+
}
276+
ops = append(ops, mso)
277+
}
278+
return ops
279+
}
280+
281+
func convertMOB2MSO(mob build.ManageOfferBuilder) *txnbuild.ManageSellOffer {
282+
mso := &txnbuild.ManageSellOffer{
283+
Amount: fmt.Sprintf("%.7f", float64(mob.MO.Amount)/math.Pow(10, 7)),
284+
OfferID: int64(mob.MO.OfferId),
285+
Price: fmt.Sprintf("%.7f", float64(mob.MO.Price.N)/float64(mob.MO.Price.D)),
286+
}
287+
if mob.O.SourceAccount != nil {
288+
mso.SourceAccount = &txnbuild.SimpleAccount{
289+
AccountID: mob.O.SourceAccount.Address(),
290+
}
291+
}
292+
293+
if mob.MO.Buying.Type == xdr.AssetTypeAssetTypeNative {
294+
mso.Buying = txnbuild.NativeAsset{}
295+
} else {
296+
var tipe, code, issuer string
297+
mob.MO.Buying.MustExtract(&tipe, &code, &issuer)
298+
mso.Buying = txnbuild.CreditAsset{
299+
Code: code,
300+
Issuer: issuer,
301+
}
302+
}
303+
304+
if mob.MO.Selling.Type == xdr.AssetTypeAssetTypeNative {
305+
mso.Selling = txnbuild.NativeAsset{}
306+
} else {
307+
var tipe, code, issuer string
308+
mob.MO.Selling.MustExtract(&tipe, &code, &issuer)
309+
mso.Selling = txnbuild.CreditAsset{
310+
Code: code,
311+
Issuer: issuer,
312+
}
313+
}
314+
315+
return mso
316+
}

cmd/trade.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212

1313
"github.com/nikhilsaraf/go-tools/multithreading"
1414
"github.com/spf13/cobra"
15-
"github.com/stellar/go/build"
1615
"github.com/stellar/go/clients/horizonclient"
1716
hProtocol "github.com/stellar/go/protocols/horizon"
1817
"github.com/stellar/go/support/config"
@@ -198,7 +197,7 @@ func makeExchangeShimSdex(
198197
options inputs,
199198
client *horizonclient.Client,
200199
ieif *plugins.IEIF,
201-
network build.Network,
200+
network string,
202201
threadTracker *multithreading.ThreadTracker,
203202
tradingPair *model.TradingPair,
204203
) (api.ExchangeShim, *plugins.SDEX) {
@@ -290,7 +289,7 @@ func makeExchangeShimSdex(
290289

291290
func makeStrategy(
292291
l logger.Logger,
293-
network build.Network,
292+
network string,
294293
botConfig trader.BotConfig,
295294
client *horizonclient.Client,
296295
sdex *plugins.SDEX,
@@ -698,7 +697,7 @@ func deleteAllOffersAndExit(
698697
l.Infof("created %d operations to delete offers\n", len(dOps))
699698

700699
if len(dOps) > 0 {
701-
e := exchangeShim.SubmitOpsSynch(dOps, func(hash string, e error) {
700+
e := exchangeShim.SubmitOpsSynch(api.ConvertOperation2TM(dOps), func(hash string, e error) {
702701
if e != nil {
703702
logger.Fatal(l, e)
704703
return

glide.lock

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import:
1212
version: a599ed95b928a7bdcee21cee4999efd05e43c2df
1313
subpackages:
1414
- build
15-
- clients/horizon
1615
- clients/horizonclient
1716
- support/config
1817
- support/errors

gui/backend/api_server.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"path/filepath"
1111
"strings"
1212

13-
"github.com/stellar/go/clients/horizon"
1413
"github.com/stellar/go/clients/horizonclient"
1514
"github.com/stellar/kelp/support/kelpos"
1615
)
@@ -27,8 +26,6 @@ type APIServer struct {
2726
ccxtRestUrl string
2827
apiTestNet *horizonclient.Client
2928
apiPubNet *horizonclient.Client
30-
apiTestNetOld *horizon.Client
31-
apiPubNetOld *horizon.Client
3229
cachedOptionsMetadata metadata
3330
}
3431

@@ -56,14 +53,6 @@ func MakeAPIServer(kos *kelpos.KelpOS, horizonTestnetURI string, horizonPubnetUR
5653
HorizonURL: horizonPubnetURI,
5754
HTTP: http.DefaultClient,
5855
}
59-
apiTestNetOld := &horizon.Client{
60-
URL: horizonTestnetURI,
61-
HTTP: http.DefaultClient,
62-
}
63-
apiPubNetOld := &horizon.Client{
64-
URL: horizonPubnetURI,
65-
HTTP: http.DefaultClient,
66-
}
6756

6857
optionsMetadata, e := loadOptionsMetadata()
6958
if e != nil {
@@ -81,8 +70,6 @@ func MakeAPIServer(kos *kelpos.KelpOS, horizonTestnetURI string, horizonPubnetUR
8170
ccxtRestUrl: ccxtRestUrl,
8271
apiTestNet: apiTestNet,
8372
apiPubNet: apiPubNet,
84-
apiTestNetOld: apiTestNetOld,
85-
apiPubNetOld: apiPubNetOld,
8673
cachedOptionsMetadata: optionsMetadata,
8774
}, nil
8875
}

gui/backend/autogenerate_bot.go

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import (
66
"log"
77
"net/http"
88

9-
"github.com/stellar/go/build"
109
"github.com/stellar/go/clients/horizonclient"
1110
"github.com/stellar/go/keypair"
11+
"github.com/stellar/go/network"
1212
hProtocol "github.com/stellar/go/protocols/horizon"
13+
"github.com/stellar/go/txnbuild"
1314
"github.com/stellar/kelp/gui/model2"
1415
"github.com/stellar/kelp/plugins"
1516
"github.com/stellar/kelp/support/kelpos"
@@ -97,38 +98,62 @@ func (s *APIServer) autogenerateBot(w http.ResponseWriter, r *http.Request) {
9798
}
9899

99100
func (s *APIServer) setupAccount(address string, signer string, botName string) error {
100-
_, e := s.checkFundAccount(address, botName)
101+
fundedAccount, e := s.checkFundAccount(address, botName)
101102
if e != nil {
102103
return fmt.Errorf("error checking and funding account: %s\n", e)
103104
}
104105

105-
client := s.apiTestNetOld
106-
txn, e := build.Transaction(
107-
build.SourceAccount{AddressOrSeed: address},
108-
build.AutoSequence{SequenceProvider: client},
109-
build.TestNetwork,
110-
build.Trust("COUPON", "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"),
111-
build.Payment(
112-
build.Destination{AddressOrSeed: address},
113-
build.CreditAmount{Code: "COUPON", Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", Amount: "1000.0"},
114-
build.SourceAccount{AddressOrSeed: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"},
115-
),
116-
)
106+
var txOps []txnbuild.Operation
107+
trustOp := txnbuild.ChangeTrust{
108+
Line: txnbuild.CreditAsset{
109+
Code: "COUPON",
110+
Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI",
111+
},
112+
}
113+
txOps = append(txOps, &trustOp)
114+
115+
paymentOp := txnbuild.Payment{
116+
Destination: address,
117+
Amount: "1000.0",
118+
Asset: txnbuild.CreditAsset{
119+
Code: "COUPON",
120+
Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI",
121+
},
122+
SourceAccount: &txnbuild.SimpleAccount{AccountID: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"},
123+
}
124+
txOps = append(txOps, &paymentOp)
125+
126+
tx := txnbuild.Transaction{
127+
SourceAccount: fundedAccount,
128+
Operations: txOps,
129+
Timebounds: txnbuild.NewInfiniteTimeout(),
130+
Network: network.TestNetworkPassphrase,
131+
BaseFee: 100,
132+
}
133+
e = tx.Build()
117134
if e != nil {
118135
return fmt.Errorf("cannot create trustline transaction for account %s for bot '%s': %s\n", address, botName, e)
119136
}
120137

121-
txnS, e := txn.Sign(signer, issuerSeed)
122-
if e != nil {
123-
return fmt.Errorf("cannot sign trustline transaction for account %s for bot '%s': %s\n", address, botName, e)
138+
for _, s := range []string{signer, issuerSeed} {
139+
kp, e := keypair.Parse(s)
140+
if e != nil {
141+
return fmt.Errorf("cannot parse seed %s required for signing: %s\n", s, e)
142+
}
143+
144+
e = tx.Sign(kp.(*keypair.Full))
145+
if e != nil {
146+
return fmt.Errorf("cannot sign trustline transaction for account %s for bot '%s': %s\n", address, botName, e)
147+
}
124148
}
125149

126-
txn64, e := txnS.Base64()
150+
txn64, e := tx.Base64()
127151
if e != nil {
128152
return fmt.Errorf("cannot convert trustline transaction to base64 for account %s for bot '%s': %s\n", address, botName, e)
129153
}
130154

131-
resp, e := client.SubmitTransaction(txn64)
155+
client := s.apiTestNet
156+
resp, e := client.SubmitTransactionXDR(txn64)
132157
if e != nil {
133158
return fmt.Errorf("error submitting change trust transaction for address %s for bot '%s': %s\n", address, botName, e)
134159
}
@@ -165,6 +190,22 @@ func (s *APIServer) checkFundAccount(address string, botName string) (*hProtocol
165190
return nil, fmt.Errorf("error funding address %s for bot '%s': %s\n", address, botName, e)
166191
}
167192
log.Printf("successfully funded account %s for bot '%s': %s\n", address, botName, fundResponse)
193+
194+
// refetch account to confirm
195+
account, e = s.apiTestNet.AccountDetail(horizonclient.AccountRequest{AccountID: address})
196+
if e != nil {
197+
var herr *horizonclient.Error
198+
switch t := e.(type) {
199+
case *horizonclient.Error:
200+
herr = t
201+
case horizonclient.Error:
202+
herr = &t
203+
default:
204+
return nil, fmt.Errorf("unexpected error when checking for existence of account %s for bot '%s': %s", address, botName, e)
205+
}
206+
207+
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)
208+
}
168209
return &account, nil
169210
}
170211

gui/backend/get_bot_info.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"strings"
1212
"time"
1313

14-
"github.com/stellar/go/clients/horizon"
1514
"github.com/stellar/go/clients/horizonclient"
1615
hProtocol "github.com/stellar/go/protocols/horizon"
1716
"github.com/stellar/go/support/config"
@@ -215,7 +214,7 @@ func getNativeBalance(account hProtocol.Account) (float64, error) {
215214
return balance, nil
216215
}
217216

218-
func getCreditBalance(account hProtocol.Account, asset horizon.Asset) (float64, error) {
217+
func getCreditBalance(account hProtocol.Account, asset hProtocol.Asset) (float64, error) {
219218
balanceString := account.GetCreditBalance(asset.Code, asset.Issuer)
220219
balance, e := strconv.ParseFloat(balanceString, 64)
221220
if e != nil {

0 commit comments

Comments
 (0)