From cb4e7fa3331b0c89fcfb3134e2e5fd911434d308 Mon Sep 17 00:00:00 2001 From: oliha Date: Tue, 14 May 2019 12:40:49 +0100 Subject: [PATCH 1/2] add manage_buy_offer operation --- txnbuild/example_test.go | 30 ++++++++++++++ txnbuild/manage_buy_offer.go | 59 ++++++++++++++++++++++++++++ txnbuild/transaction_test.go | 76 ++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 txnbuild/manage_buy_offer.go diff --git a/txnbuild/example_test.go b/txnbuild/example_test.go index 0ce3c7ee16..1842530512 100644 --- a/txnbuild/example_test.go +++ b/txnbuild/example_test.go @@ -434,3 +434,33 @@ func ExamplePathPayment() { // Output: AAAAAH4RyzTWNfXhqwLUoCw91aWkZtgIzY8SAVkIPc0uFVmYAAAAZAAMoj8AAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAAF9eEAAAAAAH4RyzTWNfXhqwLUoCw91aWkZtgIzY8SAVkIPc0uFVmYAAAAAAAAAAAAmJaAAAAAAQAAAAFBQkNEAAAAAODcbeFyXKxmUWK1L6znNbKKIkPkHRJNbLktcKPqLnLFAAAAAAAAAAEuFVmYAAAAQOGE+w2bvIp8JQIPIFXWk5kO77cNUOlPZwlItA5V68/qmZTbJWq8wqdZtjELkZtNcQQX4x8EToShbn5nitG3RA4= } + +func ExampleManageBuyOffer() { + kp, _ := keypair.Parse("SBZVMB74Z76QZ3ZOY7UTDFYKMEGKW5XFJEB6PFKBF4UYSSWHG4EDH7PY") + client := horizonclient.DefaultTestNetClient + ar := horizonclient.AccountRequest{AccountID: kp.Address()} + sourceAccount, err := client.AccountDetail(ar) + check(err) + + buyOffer := ManageBuyOffer{ + Selling: NativeAsset{}, + Buying: CreditAsset{"ABCD", "GDQNY3PBOJOKYZSRMK2S7LHHGWZIUISD4QORETLMXEWXBI7KFZZMKTL3"}, + Amount: "100", + Price: "0.01", + OfferID: 0, + } + + tx := Transaction{ + SourceAccount: &sourceAccount, + Operations: []Operation{&buyOffer}, + Timebounds: NewInfiniteTimeout(), + Network: network.TestNetworkPassphrase, + } + + txe, err := tx.BuildSignEncode(kp.(*keypair.Full)) + check(err) + fmt.Println(txe) + + // Output: AAAAAH4RyzTWNfXhqwLUoCw91aWkZtgIzY8SAVkIPc0uFVmYAAAAZAAMoj8AAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAAODcbeFyXKxmUWK1L6znNbKKIkPkHRJNbLktcKPqLnLFAAAAADuaygAAAAABAAAAZAAAAAAAAAAAAAAAAAAAAAEuFVmYAAAAQPh8h1TrzDpcgzB/VE8V0X2pFGV8/JyuYrx0I5bRfBJuLJr0l8yL1isP1wZjvMdX7fNiktwSLuUuj749nWA6wAo= + +} diff --git a/txnbuild/manage_buy_offer.go b/txnbuild/manage_buy_offer.go new file mode 100644 index 0000000000..836325932e --- /dev/null +++ b/txnbuild/manage_buy_offer.go @@ -0,0 +1,59 @@ +package txnbuild + +import ( + "github.com/stellar/go/amount" + "github.com/stellar/go/price" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// ManageBuyOffer represents the Stellar manage buy offer operation. See +// https://www.stellar.org/developers/guides/concepts/list-of-operations.html +type ManageBuyOffer struct { + Selling Asset + Buying Asset + Amount string + Price string + OfferID int64 + SourceAccount Account +} + +// BuildXDR for ManageBuyOffer returns a fully configured XDR Operation. +func (mo *ManageBuyOffer) BuildXDR() (xdr.Operation, error) { + xdrSelling, err := mo.Selling.ToXDR() + if err != nil { + return xdr.Operation{}, errors.Wrap(err, "failed to set XDR 'Selling' field") + } + + xdrBuying, err := mo.Buying.ToXDR() + if err != nil { + return xdr.Operation{}, errors.Wrap(err, "failed to set XDR 'Buying' field") + } + + xdrAmount, err := amount.Parse(mo.Amount) + if err != nil { + return xdr.Operation{}, errors.Wrap(err, "failed to parse 'Amount'") + } + + xdrPrice, err := price.Parse(mo.Price) + if err != nil { + return xdr.Operation{}, errors.Wrap(err, "failed to parse 'Price'") + } + + opType := xdr.OperationTypeManageBuyOffer + xdrOp := xdr.ManageBuyOfferOp{ + Selling: xdrSelling, + Buying: xdrBuying, + BuyAmount: xdrAmount, + Price: xdrPrice, + OfferId: xdr.Int64(mo.OfferID), + } + body, err := xdr.NewOperationBody(opType, xdrOp) + if err != nil { + return xdr.Operation{}, errors.Wrap(err, "failed to build XDR OperationBody") + } + + op := xdr.Operation{Body: body} + SetOpSourceAccount(&op, mo.SourceAccount) + return op, nil +} diff --git a/txnbuild/transaction_test.go b/txnbuild/transaction_test.go index 3af5fb1608..61ef5821ec 100644 --- a/txnbuild/transaction_test.go +++ b/txnbuild/transaction_test.go @@ -632,3 +632,79 @@ func TestMemoReturn(t *testing.T) { expected := "AAAAAH4RyzTWNfXhqwLUoCw91aWkZtgIzY8SAVkIPc0uFVmYAAAAZAAMLgoAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAsAAAAAAAAAAQAAAAAAAAABLhVZmAAAAEAuLFTunY08pbWKompoepHdazLmr7uePUSOzA4P33+SVRKWiu+h2tngOsP8hga+wpLJXT9l/0uMQ3iziRVUrh0K" assert.Equal(t, expected, received, "Base 64 XDR should match") } + +func TestManageBuyOfferNewOffer(t *testing.T) { + kp0 := newKeypair0() + kp1 := newKeypair1() + sourceAccount := NewSimpleAccount(kp1.Address(), int64(41137196761092)) + + buyOffer := ManageBuyOffer{ + Selling: NativeAsset{}, + Buying: CreditAsset{"ABCD", kp0.Address()}, + Amount: "100", + Price: "0.01", + OfferID: 0, + } + + tx := Transaction{ + SourceAccount: &sourceAccount, + Operations: []Operation{&buyOffer}, + Timebounds: NewInfiniteTimeout(), + Network: network.TestNetworkPassphrase, + } + + received := buildSignEncode(t, tx, kp1) + // https://www.stellar.org/laboratory/#xdr-viewer?input=AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R%2BAAAAZAAAJWoAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAAODcbeFyXKxmUWK1L6znNbKKIkPkHRJNbLktcKPqLnLFAAAAADuaygAAAAABAAAAZAAAAAAAAAAAAAAAAAAAAAHSh2R%2BAAAAQHwuorW7BvBwJAz%2BETSteeDZ9UKhox1y1BqJLvaIkWSr5rNbOpimjWQxrUNQoy%2B%2BwmtY8tiMSv3Jbz8Dd4QTaQU%3D&type=TransactionEnvelope&network=test + expected := "AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAZAAAJWoAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAAODcbeFyXKxmUWK1L6znNbKKIkPkHRJNbLktcKPqLnLFAAAAADuaygAAAAABAAAAZAAAAAAAAAAAAAAAAAAAAAHSh2R+AAAAQHwuorW7BvBwJAz+ETSteeDZ9UKhox1y1BqJLvaIkWSr5rNbOpimjWQxrUNQoy++wmtY8tiMSv3Jbz8Dd4QTaQU=" + assert.Equal(t, expected, received, "Base 64 XDR should match") +} + +func TestManageBuyOfferDeleteOffer(t *testing.T) { + kp1 := newKeypair1() + sourceAccount := NewSimpleAccount(kp1.Address(), int64(41137196761105)) + + buyOffer := ManageBuyOffer{ + Selling: NativeAsset{}, + Buying: CreditAsset{"ABCD", kp1.Address()}, + Amount: "0", + Price: "0.01", + OfferID: int64(2921622), + } + + tx := Transaction{ + SourceAccount: &sourceAccount, + Operations: []Operation{&buyOffer}, + Timebounds: NewInfiniteTimeout(), + Network: network.TestNetworkPassphrase, + } + + received := buildSignEncode(t, tx, kp1) + // https://www.stellar.org/laboratory/#xdr-viewer?input=AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R%2BAAAAZAAAJWoAAAASAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R%2BAAAAAAAAAAAAAAABAAAAZAAAAAAALJSWAAAAAAAAAAHSh2R%2BAAAAQItno%2BcpmUYFvxLcYVaDonTV3dmvzz%2B2SLzKRrYoXOqK8wCZjcP%2FkgzPMmXhTtF2tgQ9qb0rAIYpH9%2FrjtZPBgY%3D&type=TransactionEnvelope&network=test + expected := "AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAZAAAJWoAAAASAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAAAAAAAAAAAABAAAAZAAAAAAALJSWAAAAAAAAAAHSh2R+AAAAQItno+cpmUYFvxLcYVaDonTV3dmvzz+2SLzKRrYoXOqK8wCZjcP/kgzPMmXhTtF2tgQ9qb0rAIYpH9/rjtZPBgY=" + assert.Equal(t, expected, received, "Base 64 XDR should match") +} + +func TestManageBuyOfferUpdateOffer(t *testing.T) { + kp1 := newKeypair1() + sourceAccount := NewSimpleAccount(kp1.Address(), int64(41137196761097)) + + buyOffer := ManageBuyOffer{ + Selling: NativeAsset{}, + Buying: CreditAsset{"ABCD", kp1.Address()}, + Amount: "50", + Price: "0.02", + OfferID: int64(2921622), + } + + tx := Transaction{ + SourceAccount: &sourceAccount, + Operations: []Operation{&buyOffer}, + Timebounds: NewInfiniteTimeout(), + Network: network.TestNetworkPassphrase, + } + + received := buildSignEncode(t, tx, kp1) + // https://www.stellar.org/laboratory/#xdr-viewer?input=AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R%2BAAAAZAAAJWoAAAAKAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R%2BAAAAAB3NZQAAAAABAAAAMgAAAAAALJSWAAAAAAAAAAHSh2R%2BAAAAQK%2FsasTxgNqvkz3dGaDOyUgfa9UAAmUBmgiyaQU1dMlNNvTVH1D7PQKXkTooWmb6qK7Ee8vaTCFU6gGmShhA9wE%3D&type=TransactionEnvelope&network=test + expected := "AAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAZAAAJWoAAAAKAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQkNEAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAAB3NZQAAAAABAAAAMgAAAAAALJSWAAAAAAAAAAHSh2R+AAAAQK/sasTxgNqvkz3dGaDOyUgfa9UAAmUBmgiyaQU1dMlNNvTVH1D7PQKXkTooWmb6qK7Ee8vaTCFU6gGmShhA9wE=" + assert.Equal(t, expected, received, "Base 64 XDR should match") +} From eccf461d1fb69dafcdcbf6370dd82d432a510c08 Mon Sep 17 00:00:00 2001 From: oliha Date: Tue, 14 May 2019 12:41:55 +0100 Subject: [PATCH 2/2] update changelog --- txnbuild/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/txnbuild/CHANGELOG.md b/txnbuild/CHANGELOG.md index eec595117d..745532f86e 100644 --- a/txnbuild/CHANGELOG.md +++ b/txnbuild/CHANGELOG.md @@ -8,6 +8,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/). * In addition to account responses from horizon, transactions and operations can now be built with txnbuild.SimpleAccount structs constructed locally. * Added `MaxTrustlineLimit` which represents the maximum value for a trustline limit. * ChangeTrust operation with no `Limit` field set now defaults to `MaxTrustlineLimit`. +* Add support for building `ManageBuyOffer` operation. ## [v1.1.0](https://github.com/stellar/go/releases/tag/horizonclient-v1.1.0) - 2019-02-02