From 27508060de312db4c67d4316ce8588e7fb0488a3 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 5 Nov 2021 09:54:11 -0700 Subject: [PATCH] Upgrade to use stellar/go@horizonclient-v8.0.0 (#748) * Upgrade stellar/go to horizonclient-v8.0.0 * Fix myriad of xdr related things that have changed * Update to Go 1.17 * Fix build tests * Add lib/pq dep that used to be indirectly imported via xdr * Shift lib/pq import * Update price int64 handling * Remove panic on non-exact trade when precision is lost --- .circleci/config.yml | 12 +- api/exchange.go | 10 +- api/strategy.go | 2 +- go.mod | 22 +- go.sum | 71 +-- gui/backend/autogenerate_bot.go | 4 +- gui/backend/upsert_bot_config.go | 4 +- plugins/batchedExchange.go | 2 +- plugins/composeStrategy.go | 2 +- plugins/deleteSideStrategy.go | 2 +- plugins/mirrorStrategy.go | 2 +- plugins/sdex.go | 9 +- plugins/sellSideStrategy.go | 2 +- plugins/submitFilter.go | 2 +- stellargohorizonclientv300/build/README.md | 3 + .../build/account_merge.go | 53 ++ .../build/account_merge_test.go | 70 +++ .../build/allow_trust.go | 80 +++ .../build/allow_trust_test.go | 136 +++++ stellargohorizonclientv300/build/asset.go | 46 ++ .../build/asset_test.go | 93 +++ .../build/bump_sequence.go | 55 ++ .../build/bump_sequence_test.go | 56 ++ .../build/change_trust.go | 104 ++++ .../build/change_trust_test.go | 134 +++++ .../build/create_account.go | 62 ++ .../build/create_account_test.go | 75 +++ stellargohorizonclientv300/build/inflation.go | 37 ++ .../build/inflation_test.go | 44 ++ stellargohorizonclientv300/build/main.go | 249 ++++++++ stellargohorizonclientv300/build/main_test.go | 540 ++++++++++++++++++ .../build/manage_data.go | 75 +++ .../build/manage_data_test.go | 166 ++++++ .../build/manage_offer.go | 133 +++++ .../build/manage_offer_test.go | 172 ++++++ stellargohorizonclientv300/build/operation.go | 19 + stellargohorizonclientv300/build/payment.go | 156 +++++ .../build/payment_test.go | 284 +++++++++ .../build/set_options.go | 255 +++++++++ .../build/set_options_test.go | 209 +++++++ stellargohorizonclientv300/build/testing.go | 28 + .../build/transaction.go | 358 ++++++++++++ .../build/transaction_envelope.go | 128 +++++ .../build/transaction_envelope_test.go | 53 ++ .../build/transaction_test.go | 186 ++++++ stellargohorizonclientv300/build/util.go | 59 ++ support/postgresdb/postgresdb.go | 3 + terminator/terminator.go | 14 +- trader/trader.go | 2 +- 49 files changed, 4192 insertions(+), 91 deletions(-) create mode 100644 stellargohorizonclientv300/build/README.md create mode 100644 stellargohorizonclientv300/build/account_merge.go create mode 100644 stellargohorizonclientv300/build/account_merge_test.go create mode 100644 stellargohorizonclientv300/build/allow_trust.go create mode 100644 stellargohorizonclientv300/build/allow_trust_test.go create mode 100644 stellargohorizonclientv300/build/asset.go create mode 100644 stellargohorizonclientv300/build/asset_test.go create mode 100644 stellargohorizonclientv300/build/bump_sequence.go create mode 100644 stellargohorizonclientv300/build/bump_sequence_test.go create mode 100644 stellargohorizonclientv300/build/change_trust.go create mode 100644 stellargohorizonclientv300/build/change_trust_test.go create mode 100644 stellargohorizonclientv300/build/create_account.go create mode 100644 stellargohorizonclientv300/build/create_account_test.go create mode 100644 stellargohorizonclientv300/build/inflation.go create mode 100644 stellargohorizonclientv300/build/inflation_test.go create mode 100644 stellargohorizonclientv300/build/main.go create mode 100644 stellargohorizonclientv300/build/main_test.go create mode 100644 stellargohorizonclientv300/build/manage_data.go create mode 100644 stellargohorizonclientv300/build/manage_data_test.go create mode 100644 stellargohorizonclientv300/build/manage_offer.go create mode 100644 stellargohorizonclientv300/build/manage_offer_test.go create mode 100644 stellargohorizonclientv300/build/operation.go create mode 100644 stellargohorizonclientv300/build/payment.go create mode 100644 stellargohorizonclientv300/build/payment_test.go create mode 100644 stellargohorizonclientv300/build/set_options.go create mode 100644 stellargohorizonclientv300/build/set_options_test.go create mode 100644 stellargohorizonclientv300/build/testing.go create mode 100644 stellargohorizonclientv300/build/transaction.go create mode 100644 stellargohorizonclientv300/build/transaction_envelope.go create mode 100644 stellargohorizonclientv300/build/transaction_envelope_test.go create mode 100644 stellargohorizonclientv300/build/transaction_test.go create mode 100644 stellargohorizonclientv300/build/util.go create mode 100644 support/postgresdb/postgresdb.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 21c054e92..e73894204 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -95,9 +95,9 @@ commands: jobs: # test performs all package tests from Kelp - test_1_13: + test_1_17: docker: - - image: circleci/golang:1.13 + - image: circleci/golang:1.17 - image: franzsee/ccxt-rest:v0.0.4 command: ["node", "/usr/local/bin/ccxt-rest"] - image: circleci/postgres:12.1-alpine-ram @@ -109,9 +109,9 @@ jobs: - test_kelp # test runs all the strategies as integration tests, one after the other so there's no interference - test_1_13__integration: + test_1_17__integration: docker: - - image: circleci/golang:1.13 + - image: circleci/golang:1.17 steps: # limit to only the key strategies because of rate limit issues, remaining strategies: sell, pendulum # don't list sell_twap strategy for now because it requires a db to be enabled in sample_trader.cfg @@ -130,5 +130,5 @@ workflows: version: 2 build-and-test: jobs: - - test_1_13 - - test_1_13__integration + - test_1_17 + - test_1_17__integration diff --git a/api/exchange.go b/api/exchange.go index 9d3966399..af2d507f2 100644 --- a/api/exchange.go +++ b/api/exchange.go @@ -4,11 +4,11 @@ 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" + "github.com/stellar/kelp/stellargohorizonclientv300/build" ) // ExchangeAPIKey specifies API credentials for an exchange @@ -253,8 +253,8 @@ func ConvertOperation2TM(ops []txnbuild.Operation) []build.TransactionMutator { }, build.OfferID(mso.OfferID), ) - if mso.SourceAccount != nil { - mob.Mutate(build.SourceAccount{AddressOrSeed: mso.SourceAccount.GetAccountID()}) + if mso.SourceAccount != "" { + mob.Mutate(build.SourceAccount{AddressOrSeed: mso.SourceAccount}) } } else { panic(fmt.Sprintf("could not convert txnbuild.Operation to build.TransactionMutator: %v\n", o)) @@ -303,9 +303,7 @@ func convertMOB2MSO(mob build.ManageOfferBuilder) *txnbuild.ManageSellOffer { 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(), - } + mso.SourceAccount = mob.O.SourceAccount.Address() } if mob.MO.Buying.Type == xdr.AssetTypeAssetTypeNative { diff --git a/api/strategy.go b/api/strategy.go index 7a0de795f..afd86b9ed 100644 --- a/api/strategy.go +++ b/api/strategy.go @@ -1,7 +1,7 @@ package api import ( - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/kelp/model" ) diff --git a/go.mod b/go.mod index 3e0d4e427..6db1059d6 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,13 @@ module github.com/stellar/kelp go 1.13 require ( - cloud.google.com/go v0.84.0 // indirect github.com/Beldur/kraken-go-api-client v0.0.0-20180126083054-8d8ccfe4cc60 github.com/BurntSushi/toml v0.3.1 github.com/PagerDuty/go-pagerduty v0.0.0-20180821050606-635c5ce27149 github.com/adshao/go-binance/v2 v2.3.0 github.com/akavel/rsrc v0.9.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect - github.com/asticode/go-astilectron v0.8.1-0.20190411111508-8e68f812e8a2 // indirect - github.com/asticode/go-astilectron-bootstrap v0.0.0-20190816065004-25b857285999 // indirect + github.com/asticode/go-astilectron v0.8.1-0.20190411111508-8e68f812e8a2 + github.com/asticode/go-astilectron-bootstrap v0.0.0-20190816065004-25b857285999 github.com/asticode/go-astilectron-bundler v0.0.0-20190426172205-155c2a10bbb1 // indirect github.com/asticode/go-astilog v1.1.0 github.com/asticode/go-astitools v1.2.1-0.20190929114647-d157a994ecbd // indirect @@ -31,6 +29,7 @@ require ( github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7 // indirect github.com/hashicorp/hcl v1.0.1-0.20200422214639-569ae818ccb3 // indirect github.com/julienschmidt/httprouter v1.3.1-0.20200114094804-8c9f31f047a3 // indirect + github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/kr/session v0.1.1-0.20191204081249-b3d751351733 // indirect github.com/lechengfan/googleauth v0.1.1-0.20181105235754-7595ba02fbce github.com/lib/pq v1.2.0 @@ -39,8 +38,9 @@ require ( github.com/mattn/go-isatty v0.0.13-0.20200128103942-cb30d6282491 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/nikhilsaraf/go-tools v0.0.0-20190326212736-a26df67722de + github.com/onsi/ginkgo v1.7.0 + github.com/onsi/gomega v1.4.3 github.com/openlyinc/pointy v1.1.2 - github.com/pelletier/go-toml v1.9.0 // indirect github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -48,21 +48,13 @@ require ( github.com/sam-kamerer/go-plister v1.2.1-0.20200203020647-924bd04c389c // indirect github.com/segmentio/go-loggly v0.5.1-0.20180728234623-7a70408c3650 // indirect github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd - github.com/sirupsen/logrus v1.4.1 // indirect github.com/spf13/afero v1.2.3-0.20200421135842-c17d29330031 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v0.0.1 github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.6.3-0.20200421151844-c42a305a4bd2 // indirect - github.com/stellar/go v0.0.0-20200428193902-20797e3e2f1a - github.com/stellar/go-xdr v0.0.0-20201028102745-f80a23dac78a // indirect - github.com/stretchr/objx v0.3.0 // indirect - github.com/stretchr/testify v1.6.1 + github.com/stellar/go v0.0.0-20211007183021-ea18bbab9344 + github.com/stretchr/testify v1.7.0 github.com/subosito/gotenv v1.2.1-0.20190917103637-de67a6614a4d // indirect - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect - golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect - golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect gopkg.in/ini.v1 v1.55.0 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index bb68f22fd..e6721c040 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -bitbucket.org/ww/goautoneg v0.0.0-20120707110453-75cd24fc2f2c/go.mod h1:1vhO7Mn/FZMgOgDVGLy5X1mE6rq1HbkBdkF/yj8zkcg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -16,6 +15,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -31,6 +31,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -47,12 +48,12 @@ github.com/Beldur/kraken-go-api-client v0.0.0-20180126083054-8d8ccfe4cc60/go.mod github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM= +github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PagerDuty/go-pagerduty v0.0.0-20180821050606-635c5ce27149 h1:txbpP8qPBR7ek8CmKtkVUwjdSAq7ql+6+3AVaT2pMyI= github.com/PagerDuty/go-pagerduty v0.0.0-20180821050606-635c5ce27149/go.mod h1:6hH58nzwYc9mw+TPyM1anW0ivbI0ti4lYc+ZBaKmWts= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/adjust/goautoneg v0.0.0-20150426214442-d788f35a0315/go.mod h1:4U522XvlkqOY2AVBUM7ISHODDb6tdB+KAXfGaBDsWts= github.com/adshao/go-binance/v2 v2.3.0 h1:SZrqGZb71wnXzkl4hg2GT4tye78jo8b7wi97mMif5XQ= github.com/adshao/go-binance/v2 v2.3.0/go.mod h1:o+84WK3DQxq9vEKV9ncRcQi+J7RFCGhM27osbECZiJQ= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f h1:zvClvFQwU++UpIUBGC8YmDlfhUrweEy1R1Fj1gu5iIM= @@ -61,13 +62,11 @@ github.com/akavel/rsrc v0.9.0 h1:HwUDC0+tMFWqN4D5G+o5siGD4oVsC3jn6zM8ocjc3nY= github.com/akavel/rsrc v0.9.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asticode/go-astiamqp v1.0.0/go.mod h1:PDHG8FjHJDtbDNNHixFCm80+7Ma1dKvwYl325Mj5DI4= github.com/asticode/go-astilectron v0.8.1-0.20190411111508-8e68f812e8a2 h1:aqlD+lwE4sOxXntDymLX8L0hxPzoDoyVVf/CxVVZ9lU= github.com/asticode/go-astilectron v0.8.1-0.20190411111508-8e68f812e8a2/go.mod h1:XN7r4w/s0Eu7D5TgmXuPN07sO8CmYHg95kw2EuW15nE= @@ -85,7 +84,7 @@ github.com/asticode/go-bindata v1.0.0 h1:5whO0unjdx2kbAbzoBMS3307jKAEf3oQ1lJcx5R github.com/asticode/go-bindata v1.0.0/go.mod h1:t/Y+/iCLrvaYkv8Y6PscRnyUeYzy9y9+8JC9CMcKdHY= github.com/auth0/go-jwt-middleware v1.0.0 h1:76t55qLQu3xjMFbkirbSCA8ZPcO1ny+20Uq1wkSTRDE= github.com/auth0/go-jwt-middleware v1.0.0/go.mod h1:nX2S0GmCyl087kdNSSItfOvMYokq5PSTG1yGIP5Le4U= -github.com/aws/aws-sdk-go v1.25.25/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.39.5/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -119,9 +118,6 @@ github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMS github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -159,8 +155,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobuffalo/packr v1.12.1/go.mod h1:H2dZhQFqHeZwr/5A/uGQkBp7xYuMGuzXFeKhYdcz5No= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -192,7 +188,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -225,6 +220,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -232,14 +228,11 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= @@ -288,7 +281,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jarcoal/httpmock v0.0.0-20161210151336-4442edb3db31 h1:Aw95BEvxJ3K6o9GGv5ppCd1P8hkeIeEJ30FO+OhOJpM= github.com/jarcoal/httpmock v0.0.0-20161210151336-4442edb3db31/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -313,7 +307,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGi github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.0.0-20150520163514-e6ac2fc51e89/go.mod h1:Bvhd+E3laJ0AVkG0c9rmtZcnhV0HQ3+c3YxxqTvc/gA= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -321,10 +314,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/session v0.1.0/go.mod h1:lMl9UjoVzvWb8fhrlB6LYfKyfj1nAX8vxa8hTF0usSc= github.com/kr/session v0.1.1-0.20191204081249-b3d751351733 h1:z2CJ5+BAvhBAPrCkXcA4GD8SouziJa8oC0k1VSYJnn8= github.com/kr/session v0.1.1-0.20191204081249-b3d751351733/go.mod h1:fqBtQaOb2WsCMrsYWoTQL+bCXU1840pXFJHP6+0xfoU= -github.com/kr/text v0.0.0-20150520163712-e373e137fafd/go.mod h1:sjUstKUATFIcff4qlB53Kml0wQPtJVc/3fWrmuUmcfA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lann/builder v0.0.0-20140829050551-c603884a2c1f/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lechengfan/googleauth v0.1.1-0.20181105235754-7595ba02fbce h1:n3KbUn/otxNfcOq6WTShNGB/I5cicWFWPQYM+7esD5o= github.com/lechengfan/googleauth v0.1.1-0.20181105235754-7595ba02fbce/go.mod h1:sERadao7IFEb9c2lN5vp4ZJRny6/+NvPllXbYXsfDk0= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -359,7 +352,6 @@ github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:F github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mndrix/ps v0.0.0-20131111202200-33ddf69629c1/go.mod h1:dHgTaDInzkAqJv67VaX1IkK449M2UoBY68CZeI/bNCU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/moul/http2curl v0.0.0-20161031194548-4e24498b31db h1:eZgFHVkk9uOTaOQLC6tgjkzdp7Ays8eEVecBcfHZlJQ= @@ -367,7 +359,6 @@ github.com/moul/http2curl v0.0.0-20161031194548-4e24498b31db/go.mod h1:8UbvGypXm github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nikhilsaraf/go-tools v0.0.0-20190326212736-a26df67722de h1:VJMm5aUuiNZbm2ws8PowffaXhnTVQqZ3EGNf0k3Hjwg= github.com/nikhilsaraf/go-tools v0.0.0-20190326212736-a26df67722de/go.mod h1:GZmPchjq6JI3Qh+zHNQ+Ys+AaRoL0sMqMDP1Xtnnl20= -github.com/nullstyle/go-xdr v0.0.0-20180726165426-f4c839f75077/go.mod h1:sZZi9x5aHXGZ/RRp7Ne5rkvtDxZb7pd7vgVA+gmE35A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= @@ -378,12 +369,10 @@ github.com/openlyinc/pointy v1.1.2 h1:LywVV2BWC5Sp5v7FoP4bUD+2Yn5k0VNeRbU5vq9jUM github.com/openlyinc/pointy v1.1.2/go.mod h1:w2Sytx+0FVuMKn37xpXIAyBNhFNBIJGR/v2m7ik1WtM= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.0 h1:NOd0BRdOKpPf0SxkL3HxSQOG7rNh+4kl6PHcBPFs7Q0= github.com/pelletier/go-toml v1.9.0/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -409,7 +398,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -421,7 +409,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sam-kamerer/go-plister v1.2.1-0.20200203020647-924bd04c389c h1:cj4frQSULT29yBKYOKj48GhUZT6YuGJVF58I8FTQpmU= github.com/sam-kamerer/go-plister v1.2.1-0.20200203020647-924bd04c389c/go.mod h1:gTt1Ko2oTA5bfDYsNcLjRGyyx6LPxHIeo0ZTtTRZG2I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sebest/xff v0.0.0-20150611211316-7a36e3a787b5/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2/go.mod h1:8zLRYR5npGjaOXgPSKat5+oOh+UHd8OdbS18iqX9F6Y= github.com/segmentio/go-loggly v0.5.1-0.20180728234623-7a70408c3650 h1:Yr1MLWYr/foFfdLoUkEOtlSP2jnVUq2quXUMJAqo6o0= github.com/segmentio/go-loggly v0.5.1-0.20180728234623-7a70408c3650/go.mod h1:8zLRYR5npGjaOXgPSKat5+oOh+UHd8OdbS18iqX9F6Y= @@ -462,9 +449,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v0.0.0-20150621231900-db7ff930a189/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.6.3-0.20200421151844-c42a305a4bd2 h1:FkzJ/uy4SzYtmU+1Eq3RNWNXJD1QPuPnUf6PS0Mkscs= github.com/spf13/viper v1.6.3-0.20200421151844-c42a305a4bd2/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stellar/go v0.0.0-20200428193902-20797e3e2f1a h1:jgJljqpgUtm226Ba9n8WPMKi06AEbkzGkOXTpZO9j4E= -github.com/stellar/go v0.0.0-20200428193902-20797e3e2f1a/go.mod h1:kfZjGLxoc7P6QAk7BOrXL1qVk7gJV3+OSk4FCf0dXsM= -github.com/stellar/go-xdr v0.0.0-20180917104419-0bc96f33a18e/go.mod h1:gpOLVzy6TVYTQ3LvHSN9RJC700FkhFCpSE82u37aNRM= +github.com/stellar/go v0.0.0-20211007183021-ea18bbab9344 h1:hb8KjVXKkGNW15afGj+ycfTq7cJwoPuo9PvTFACrGGg= +github.com/stellar/go v0.0.0-20211007183021-ea18bbab9344/go.mod h1:H+AG8jyBM3bHICvpYayk0YZyRWax36FYFJJSrrO4cI4= github.com/stellar/go-xdr v0.0.0-20201028102745-f80a23dac78a h1:GnM0ArRp7EDbaTiFhSp/CLgyk2cacXxdUklqJmdJs1Q= github.com/stellar/go-xdr v0.0.0-20201028102745-f80a23dac78a/go.mod h1:yoxyU/M8nl9LKeWIoBrbDPQ7Cy+4jxRcWcOayZ4BMps= github.com/stellar/throttled v2.2.3-0.20190823235211-89d75816f59d+incompatible/go.mod h1:7CJ23pXirXBJq45DqvO6clzTEGM/l1SfKrgrzLry8b4= @@ -478,8 +464,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.1-0.20190917103637-de67a6614a4d h1:YN4gX82mT31qsizy2jRheOCrGLCs15VF9SV5XPuBvkQ= github.com/subosito/gotenv v1.2.1-0.20190917103637-de67a6614a4d/go.mod h1:GVSeM7r0P1RI1gOKYyN9IuNkhMmQwKGsjVf3ulDrdzo= @@ -491,6 +478,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v0.0.0-20170109085056-0a7f0a797cd6 h1:s0IDmR1jFyWvOK7jVIuAsmHQaGkXUuTas8NXFUOwuAI= github.com/valyala/fasthttp v0.0.0-20170109085056-0a7f0a797cd6/go.mod h1:+g/po7GqyG5E+1CNgquiIxJnsXEi5vwFn5weFujbO78= +github.com/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= +github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076 h1:KM4T3G70MiR+JtqplcYkNVoNz7pDwYaBxWBXQK804So= github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c h1:XZWnr3bsDQWAZg4Ne+cPoXRPILrNlPNQfxBuwLl43is= @@ -513,7 +502,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -533,7 +521,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -591,7 +578,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -610,6 +596,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -650,7 +637,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181217223516-dcdaa6325bcb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -686,6 +672,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210223095934-7937bea0104d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -695,6 +682,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= @@ -712,7 +700,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -725,7 +712,6 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -761,16 +747,18 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -794,6 +782,7 @@ google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBz google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -836,6 +825,7 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -845,7 +835,7 @@ google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -907,7 +897,6 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/gui/backend/autogenerate_bot.go b/gui/backend/autogenerate_bot.go index 9d2670da0..894bd85d1 100644 --- a/gui/backend/autogenerate_bot.go +++ b/gui/backend/autogenerate_bot.go @@ -157,7 +157,7 @@ func (s *APIServer) setupTestnetAccount(address string, signer string, botName s Line: txnbuild.CreditAsset{ Code: "COUPON", Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", - }, + }.MustToChangeTrustAsset(), } txOps = append(txOps, &trustOp) @@ -168,7 +168,7 @@ func (s *APIServer) setupTestnetAccount(address string, signer string, botName s Code: "COUPON", Issuer: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", }, - SourceAccount: &txnbuild.SimpleAccount{AccountID: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + SourceAccount: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", } txOps = append(txOps, &paymentOp) diff --git a/gui/backend/upsert_bot_config.go b/gui/backend/upsert_bot_config.go index e45a1bd80..37a31c2f2 100644 --- a/gui/backend/upsert_bot_config.go +++ b/gui/backend/upsert_bot_config.go @@ -417,7 +417,7 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, for _, a := range trustlines { creditAsset := txnbuild.CreditAsset{Code: a.Code, Issuer: a.Issuer} trustOp := txnbuild.ChangeTrust{ - Line: creditAsset, + Line: creditAsset.MustToChangeTrustAsset(), } txOps = append(txOps, &trustOp) log.Printf("added trust asset operation to transaction for asset: %+v\n", a) @@ -427,7 +427,7 @@ func (s *APIServer) checkAddTrustline(account hProtocol.Account, kp keypair.KP, Destination: address, Amount: "1000.0", Asset: creditAsset, - SourceAccount: &txnbuild.SimpleAccount{AccountID: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI"}, + SourceAccount: "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", } txOps = append(txOps, &paymentOp) log.Printf("added payment operation to transaction for asset because issuer was the public issuer (%s): %+v\n", "GBMMZMK2DC4FFP4CAI6KCVNCQ7WLO5A7DQU7EC7WGHRDQBZB763X4OQI", a) diff --git a/plugins/batchedExchange.go b/plugins/batchedExchange.go index 002cd80dc..c5eebee2f 100644 --- a/plugins/batchedExchange.go +++ b/plugins/batchedExchange.go @@ -9,7 +9,7 @@ import ( "strconv" "time" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" diff --git a/plugins/composeStrategy.go b/plugins/composeStrategy.go index 359f3e1f4..02a1ebc8d 100644 --- a/plugins/composeStrategy.go +++ b/plugins/composeStrategy.go @@ -6,7 +6,7 @@ import ( "github.com/stellar/kelp/api" "github.com/stellar/kelp/model" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/support/errors" "github.com/stellar/kelp/support/utils" diff --git a/plugins/deleteSideStrategy.go b/plugins/deleteSideStrategy.go index 350419e91..6e388f1df 100644 --- a/plugins/deleteSideStrategy.go +++ b/plugins/deleteSideStrategy.go @@ -3,7 +3,7 @@ package plugins import ( "log" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" diff --git a/plugins/mirrorStrategy.go b/plugins/mirrorStrategy.go index bc803c47f..2c6aa834a 100644 --- a/plugins/mirrorStrategy.go +++ b/plugins/mirrorStrategy.go @@ -10,7 +10,7 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" diff --git a/plugins/sdex.go b/plugins/sdex.go index b62531376..a41062dc0 100644 --- a/plugins/sdex.go +++ b/plugins/sdex.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "math" + "math/big" "net/http" "reflect" "strconv" @@ -14,7 +15,7 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" "github.com/pkg/errors" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" @@ -203,7 +204,7 @@ func (sdex *SDEX) DeleteOffer(offer hProtocol.Offer) txnbuild.ManageSellOffer { txOffer := utils.Offer2TxnBuildSellOffer(offer) txOffer.Amount = "0" if sdex.SourceAccount != sdex.TradingAccount { - txOffer.SourceAccount = &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount} + txOffer.SourceAccount = sdex.TradingAccount } return txOffer } @@ -349,7 +350,7 @@ func (sdex *SDEX) createModifySellOffer(offer *hProtocol.Offer, selling hProtoco result.OfferID = offer.ID } if sdex.SourceAccount != sdex.TradingAccount { - result.SourceAccount = &txnbuild.SimpleAccount{AccountID: sdex.TradingAccount} + result.SourceAccount = sdex.TradingAccount } return &result, nil @@ -856,7 +857,7 @@ func (sdex *SDEX) tradesPage2TradeHistoryResult(baseAsset hProtocol.Asset, quote if e != nil { return nil, false, fmt.Errorf("could not convert baseAmount to model.Number: %s", e) } - floatPrice := float64(t.Price.N) / float64(t.Price.D) + floatPrice, _ := big.NewRat(t.Price.N, t.Price.D).Float64() price := model.NumberFromFloat(floatPrice, sdexOrderConstraints.PricePrecision) trades = append(trades, model.Trade{ diff --git a/plugins/sellSideStrategy.go b/plugins/sellSideStrategy.go index 5a346d47b..e3049ef85 100644 --- a/plugins/sellSideStrategy.go +++ b/plugins/sellSideStrategy.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild" "github.com/stellar/kelp/api" diff --git a/plugins/submitFilter.go b/plugins/submitFilter.go index b842ca872..29edf3162 100644 --- a/plugins/submitFilter.go +++ b/plugins/submitFilter.go @@ -382,6 +382,6 @@ func convertOffer2MSO(offer hProtocol.Offer) *txnbuild.ManageSellOffer { Amount: offer.Amount, Price: offer.Price, OfferID: offer.ID, - SourceAccount: &txnbuild.SimpleAccount{AccountID: offer.Seller}, + SourceAccount: offer.Seller, } } diff --git a/stellargohorizonclientv300/build/README.md b/stellargohorizonclientv300/build/README.md new file mode 100644 index 000000000..17e858ee4 --- /dev/null +++ b/stellargohorizonclientv300/build/README.md @@ -0,0 +1,3 @@ +# build + +## This package is deprecated: use [txnbuild](../txnbuild) instead \ No newline at end of file diff --git a/stellargohorizonclientv300/build/account_merge.go b/stellargohorizonclientv300/build/account_merge.go new file mode 100644 index 000000000..67ae757e9 --- /dev/null +++ b/stellargohorizonclientv300/build/account_merge.go @@ -0,0 +1,53 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// AccountMerge groups the creation of a new AccountMergeBuilder with a call to +// Mutate. +func AccountMerge(muts ...interface{}) (result AccountMergeBuilder) { + result.Mutate(muts...) + return +} + +// AccountMergeMutator is a interface that wraps the +// MutateAccountMerge operation. types may implement this interface to +// specify how they modify an xdr.AccountMergeBuilder object +type AccountMergeMutator interface { + MutateAccountMerge(*AccountMergeBuilder) error +} + +// AccountMergeBuilder represents a transaction that is being built. +// Deprecated use txnbuild.AccountMerge instead +type AccountMergeBuilder struct { + O xdr.Operation + Destination xdr.MuxedAccount + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *AccountMergeBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case AccountMergeMutator: + err = mut.MutateAccountMerge(b) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "AccountMergeBuilder error") + return + } + } +} + +// MutateAccountMerge for Destination sets the AccountMergeBuilder's Destination field +func (m Destination) MutateAccountMerge(o *AccountMergeBuilder) error { + return setMuxedAccount(m.AddressOrSeed, &o.Destination) +} diff --git a/stellargohorizonclientv300/build/account_merge_test.go b/stellargohorizonclientv300/build/account_merge_test.go new file mode 100644 index 000000000..2eceb676c --- /dev/null +++ b/stellargohorizonclientv300/build/account_merge_test.go @@ -0,0 +1,70 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("AccountMergeBuilder Mutators", func() { + var ( + subject AccountMergeBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = AccountMergeBuilder{} + subject.Mutate(mut) + }) + + Describe("Destination", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = Destination{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.MuxedAccount", func() { + var muxed xdr.MuxedAccount + muxed.SetAddress(address) + Expect(subject.Destination.Type).To(Equal(muxed.Type)) + Expect(subject.Destination.Ed25519).To(Equal(muxed.Ed25519)) + Expect(subject.Destination.Med25519).To(Equal(muxed.Med25519)) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = Destination{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var muxed xdr.MuxedAccount + muxed.SetAddress(address) + Expect(subject.O.SourceAccount.Type).To(Equal(muxed.Type)) + Expect(subject.O.SourceAccount.Ed25519).To(Equal(muxed.Ed25519)) + Expect(subject.O.SourceAccount.Med25519).To(Equal(muxed.Med25519)) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + // +}) diff --git a/stellargohorizonclientv300/build/allow_trust.go b/stellargohorizonclientv300/build/allow_trust.go new file mode 100644 index 000000000..5e926bc34 --- /dev/null +++ b/stellargohorizonclientv300/build/allow_trust.go @@ -0,0 +1,80 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// AllowTrust groups the creation of a new AllowTrustBuilder with a call to Mutate. +func AllowTrust(muts ...interface{}) (result AllowTrustBuilder) { + result.Mutate(muts...) + return +} + +// AllowTrustMutator is a interface that wraps the +// MutateAllowTrust operation. types may implement this interface to +// specify how they modify an xdr.AllowTrustOp object +type AllowTrustMutator interface { + MutateAllowTrust(*xdr.AllowTrustOp) error +} + +// AllowTrustBuilder represents a transaction that is being built. +// Deprecated use txnbuild.AllowTrust instead +type AllowTrustBuilder struct { + O xdr.Operation + AT xdr.AllowTrustOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *AllowTrustBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case AllowTrustMutator: + err = mut.MutateAllowTrust(&b.AT) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "AllowTrustBuilder error") + return + } + } +} + +// MutateAllowTrust for Authorize sets the AllowTrustOp's Authorize field +func (m Authorize) MutateAllowTrust(o *xdr.AllowTrustOp) error { + o.Authorize = xdr.Uint32(m.Value) + return nil +} + +// MutateAllowTrust for Asset sets the AllowTrustOp's Asset field +func (m AllowTrustAsset) MutateAllowTrust(o *xdr.AllowTrustOp) (err error) { + length := len(m.Code) + + switch { + case length >= 1 && length <= 4: + var code xdr.AssetCode4 + byteArray := []byte(m.Code) + copy(code[:], byteArray[0:length]) + o.Asset, err = xdr.NewAssetCode(xdr.AssetTypeAssetTypeCreditAlphanum4, code) + case length >= 5 && length <= 12: + var code xdr.AssetCode12 + byteArray := []byte(m.Code) + copy(code[:], byteArray[0:length]) + o.Asset, err = xdr.NewAssetCode(xdr.AssetTypeAssetTypeCreditAlphanum12, code) + default: + err = errors.New("Asset code length is invalid") + } + + return +} + +// MutateAllowTrust for Trustor sets the AllowTrustOp's Trustor field +func (m Trustor) MutateAllowTrust(o *xdr.AllowTrustOp) error { + return setAccountId(m.Address, &o.Trustor) +} diff --git a/stellargohorizonclientv300/build/allow_trust_test.go b/stellargohorizonclientv300/build/allow_trust_test.go new file mode 100644 index 000000000..629f69d5f --- /dev/null +++ b/stellargohorizonclientv300/build/allow_trust_test.go @@ -0,0 +1,136 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("AllowTrustBuilder Mutators", func() { + + var ( + subject AllowTrustBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = AllowTrustBuilder{} + subject.Mutate(mut) + }) + + Describe("Trustor", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = Trustor{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.AT.Trustor.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = Trustor{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("AllowTrustAsset", func() { + Context("AssetTypeCreditAlphanum4", func() { + BeforeEach(func() { + mut = AllowTrustAsset{"USD"} + }) + + It("sets Asset properly", func() { + Expect(subject.AT.Asset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(*subject.AT.Asset.AssetCode4).To(Equal(xdr.AssetCode4{'U', 'S', 'D', 0})) + Expect(subject.AT.Asset.AssetCode12).To(BeNil()) + }) + }) + + Context("AssetTypeCreditAlphanum12", func() { + BeforeEach(func() { + mut = AllowTrustAsset{"ABCDEF"} + }) + + It("sets Asset properly", func() { + Expect(subject.AT.Asset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum12)) + Expect(subject.AT.Asset.AssetCode4).To(BeNil()) + Expect(*subject.AT.Asset.AssetCode12).To(Equal(xdr.AssetCode12{'A', 'B', 'C', 'D', 'E', 'F', 0, 0, 0, 0, 0, 0})) + }) + }) + + Context("asset code length invalid", func() { + Context("empty", func() { + BeforeEach(func() { + mut = AllowTrustAsset{""} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + + Context("too long", func() { + BeforeEach(func() { + mut = AllowTrustAsset{"1234567890123"} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + }) + }) + + Describe("Authorize", func() { + Context("when equal true", func() { + BeforeEach(func() { + mut = Authorize{uint32(xdr.TrustLineFlagsAuthorizedFlag)} + }) + + It("sets authorize flag properly", func() { + Expect(subject.AT.Authorize).To(Equal(xdr.Uint32(xdr.TrustLineFlagsAuthorizedFlag))) + }) + }) + + Context("when equal false", func() { + BeforeEach(func() { + subject.AT.Authorize = 0 + mut = Authorize{0} + }) + + It("sets authorize flag properly", func() { + Expect(subject.AT.Authorize).To(Equal(xdr.Uint32(0))) + }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/asset.go b/stellargohorizonclientv300/build/asset.go new file mode 100644 index 000000000..ab96e2995 --- /dev/null +++ b/stellargohorizonclientv300/build/asset.go @@ -0,0 +1,46 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// MustXDR is the panicky version of ToXDR +func (a Asset) MustXDR() xdr.Asset { + ret, err := a.ToXDR() + if err != nil { + panic(err) + } + return ret +} + +// ToXDR creates xdr.Asset object from build.Asset object +func (a Asset) ToXDR() (xdr.Asset, error) { + if a.Native { + return xdr.NewAsset(xdr.AssetTypeAssetTypeNative, nil) + } + + var issuer xdr.AccountId + err := setAccountId(a.Issuer, &issuer) + if err != nil { + return xdr.Asset{}, err + } + + length := len(a.Code) + switch { + case length >= 1 && length <= 4: + var codeArray xdr.AssetCode4 + byteArray := []byte(a.Code) + copy(codeArray[:], byteArray[0:length]) + asset := xdr.AlphaNum4{AssetCode: codeArray, Issuer: issuer} + return xdr.NewAsset(xdr.AssetTypeAssetTypeCreditAlphanum4, asset) + case length >= 5 && length <= 12: + var codeArray xdr.AssetCode12 + byteArray := []byte(a.Code) + copy(codeArray[:], byteArray[0:length]) + asset := xdr.AlphaNum12{AssetCode: codeArray, Issuer: issuer} + return xdr.NewAsset(xdr.AssetTypeAssetTypeCreditAlphanum12, asset) + default: + return xdr.Asset{}, errors.New("Asset code length is invalid") + } +} diff --git a/stellargohorizonclientv300/build/asset_test.go b/stellargohorizonclientv300/build/asset_test.go new file mode 100644 index 000000000..050485e0d --- /dev/null +++ b/stellargohorizonclientv300/build/asset_test.go @@ -0,0 +1,93 @@ +package build + +import ( + "testing" + + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestAsset_ToXDR(t *testing.T) { + var ( + issuer xdr.AccountId + issuerAddress = "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA" + ) + require.NoError(t, issuer.SetAddress(issuerAddress)) + + cases := []struct { + Name string + Asset Asset + Expected xdr.Asset + ExpectedErr string + }{ + { + Name: "Native", + Asset: NativeAsset(), + Expected: xdr.Asset{Type: xdr.AssetTypeAssetTypeNative}, + }, + { + Name: "Alphanum4", + Asset: CreditAsset("USD", issuerAddress), + Expected: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum4, + AlphaNum4: &xdr.AlphaNum4{ + AssetCode: xdr.AssetCode4{0x55, 0x53, 0x44, 0x00}, // USD + Issuer: issuer, + }, + }, + }, + { + Name: "Alphanum12", + Asset: CreditAsset("SCOTTBUCKS", issuerAddress), + Expected: xdr.Asset{ + Type: xdr.AssetTypeAssetTypeCreditAlphanum12, + AlphaNum12: &xdr.AlphaNum12{ + AssetCode: [12]byte{ + 0x53, 0x43, 0x4f, 0x54, + 0x54, 0x42, 0x55, 0x43, + 0x4b, 0x53, 0x00, 0x00, + }, //SCOTTBUCKS + Issuer: issuer, + }, + }, + }, + { + Name: "bad issuer", + Asset: CreditAsset("USD", "FUNK"), + ExpectedErr: "strkey is 4 bytes long; minimum valid length is 5", + }, + { + Name: "bad code", + Asset: CreditAsset("", issuerAddress), + ExpectedErr: "Asset code length is invalid", + }, + } + + for _, kase := range cases { + actual, err := kase.Asset.ToXDR() + + if kase.ExpectedErr != "" { + if assert.Error(t, err, ("no expected error in case: " + kase.Name)) { + assert.EqualError(t, err, kase.ExpectedErr) + } + continue + } + + if assert.NoError(t, err, "unexpected error in case: %s", kase.Name) { + assert.Equal(t, kase.Expected, actual, "invalid xdr result") + } + } +} + +func TestAsset_MustXDR(t *testing.T) { + // good + assert.NotPanics(t, func() { + NativeAsset().MustXDR() + }) + + // bad + assert.Panics(t, func() { + CreditAsset("USD", "BONK").MustXDR() + }) +} diff --git a/stellargohorizonclientv300/build/bump_sequence.go b/stellargohorizonclientv300/build/bump_sequence.go new file mode 100644 index 000000000..3f60b9e89 --- /dev/null +++ b/stellargohorizonclientv300/build/bump_sequence.go @@ -0,0 +1,55 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// BumpSequence groups the creation of a new BumpSequenceBuilder with a call +// to Mutate. Requires the BumpTo mutator to be set. +func BumpSequence(muts ...interface{}) (result BumpSequenceBuilder) { + result.Mutate(muts...) + return +} + +// BumpSequenceMutator is a interface that wraps the +// MutateBumpSequence operation. types may implement this interface to +// specify how they modify an xdr.BumpSequenceOp object +type BumpSequenceMutator interface { + MutateBumpSequence(*xdr.BumpSequenceOp) error +} + +// BumpSequenceBuilder helps to build BumpSequenceOp structs. +// Deprecated use txnbuild.BumpSequence instead +type BumpSequenceBuilder struct { + O xdr.Operation + BS xdr.BumpSequenceOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *BumpSequenceBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case BumpSequenceMutator: + err = mut.MutateBumpSequence(&b.BS) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "BumpSequenceBuilder error") + return + } + } +} + +// MutateBumpSequence for BumpTo sets the BumpSequenceOp's +// StartingBalance field +func (m BumpTo) MutateBumpSequence(o *xdr.BumpSequenceOp) (err error) { + o.BumpTo = xdr.SequenceNumber(m) + return +} diff --git a/stellargohorizonclientv300/build/bump_sequence_test.go b/stellargohorizonclientv300/build/bump_sequence_test.go new file mode 100644 index 000000000..713161681 --- /dev/null +++ b/stellargohorizonclientv300/build/bump_sequence_test.go @@ -0,0 +1,56 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("BumpSequenceBuilder Mutators", func() { + + var ( + subject BumpSequenceBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = BumpSequenceBuilder{} + subject.Mutate(mut) + }) + + Describe("BumpTo", func() { + BeforeEach(func() { mut = BumpTo(9223372036854775807) }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the value to the correct xdr.SequenceNumber", func() { + Expect(subject.BS.BumpTo).To(Equal(xdr.SequenceNumber(9223372036854775807))) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/change_trust.go b/stellargohorizonclientv300/build/change_trust.go new file mode 100644 index 000000000..073188d9f --- /dev/null +++ b/stellargohorizonclientv300/build/change_trust.go @@ -0,0 +1,104 @@ +package build + +import ( + "github.com/stellar/go/amount" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// ChangeTrust groups the creation of a new ChangeTrustBuilder with a call to Mutate. +func ChangeTrust(muts ...interface{}) (result ChangeTrustBuilder) { + result.Mutate(muts...) + return +} + +// ChangeTrustMutator is a interface that wraps the +// MutateChangeTrust operation. types may implement this interface to +// specify how they modify an xdr.ChangeTrustOp object +type ChangeTrustMutator interface { + MutateChangeTrust(*xdr.ChangeTrustOp) error +} + +// ChangeTrustBuilder represents a transaction that is being built. +// Deprecated use txnbuild.ChangeTrust instead +type ChangeTrustBuilder struct { + O xdr.Operation + CT xdr.ChangeTrustOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *ChangeTrustBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case ChangeTrustMutator: + err = mut.MutateChangeTrust(&b.CT) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "ChangeTrustBuilder error") + return + } + } +} + +// MutateChangeTrust for Asset sets the ChangeTrustOp's Line field +func (m Asset) MutateChangeTrust(o *xdr.ChangeTrustOp) (err error) { + if m.Native { + return errors.New("Native asset not allowed") + } + + asset, err := m.ToXDR() + if err != nil { + return err + } + + o.Line = asset.ToChangeTrustAsset() + return +} + +// MutateChangeTrust for Limit sets the ChangeTrustOp's Limit field +func (m Limit) MutateChangeTrust(o *xdr.ChangeTrustOp) (err error) { + o.Limit, err = amount.Parse(string(m)) + return +} + +// Trust is a helper that creates ChangeTrustBuilder +func Trust(code, issuer string, args ...interface{}) (result ChangeTrustBuilder) { + mutators := []interface{}{ + CreditAsset(code, issuer), + } + + limitSet := false + + for _, mut := range args { + mutators = append(mutators, mut) + _, isLimit := mut.(Limit) + if isLimit { + limitSet = true + } + } + + if !limitSet { + mutators = append(mutators, MaxLimit) + } + + return ChangeTrust(mutators...) +} + +// RemoveTrust is a helper that creates ChangeTrustBuilder +func RemoveTrust(code, issuer string, args ...interface{}) (result ChangeTrustBuilder) { + mutators := []interface{}{ + CreditAsset(code, issuer), + Limit("0"), + } + + mutators = append(mutators, args...) + + return ChangeTrust(mutators...) +} diff --git a/stellargohorizonclientv300/build/change_trust_test.go b/stellargohorizonclientv300/build/change_trust_test.go new file mode 100644 index 000000000..a294ecb0b --- /dev/null +++ b/stellargohorizonclientv300/build/change_trust_test.go @@ -0,0 +1,134 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("ChangeTrustBuilder Mutators", func() { + + var ( + subject ChangeTrustBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = ChangeTrustBuilder{} + subject.Mutate(mut) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("Line", func() { + Context("AssetTypeCreditAlphanum4", func() { + BeforeEach(func() { + mut = CreditAsset("USD", address) + }) + + It("sets Asset properly", func() { + Expect(subject.CT.Line.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(subject.CT.Line.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'U', 'S', 'D', 0})) + Expect(subject.CT.Line.AlphaNum12).To(BeNil()) + }) + }) + + Context("AssetTypeCreditAlphanum12", func() { + BeforeEach(func() { + mut = CreditAsset("ABCDEF", address) + }) + + It("sets Asset properly", func() { + Expect(subject.CT.Line.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum12)) + Expect(subject.CT.Line.AlphaNum4).To(BeNil()) + Expect(subject.CT.Line.AlphaNum12.AssetCode).To(Equal(xdr.AssetCode12{'A', 'B', 'C', 'D', 'E', 'F', 0, 0, 0, 0, 0, 0})) + }) + }) + + Context("asset invalid", func() { + Context("native", func() { + BeforeEach(func() { + mut = NativeAsset() + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Native asset not allowed")) + }) + }) + + Context("empty", func() { + BeforeEach(func() { + mut = CreditAsset("", address) + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + + Context("too long", func() { + BeforeEach(func() { + mut = CreditAsset("1234567890123", address) + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + }) + + Context("issuer invalid", func() { + BeforeEach(func() { + mut = CreditAsset("USD", bad) + }) + + It("failed", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + }) + + Describe("Limit", func() { + Context("sets limit properly", func() { + BeforeEach(func() { + mut = Limit("20") + }) + + It("sets limit value properly", func() { + Expect(subject.CT.Limit).To(Equal(xdr.Int64(200000000))) + }) + }) + + Context("sets max limit properly", func() { + BeforeEach(func() { + mut = MaxLimit + }) + + It("sets limit value properly", func() { + Expect(subject.CT.Limit).To(Equal(xdr.Int64(9223372036854775807))) + }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/create_account.go b/stellargohorizonclientv300/build/create_account.go new file mode 100644 index 000000000..abb5ce759 --- /dev/null +++ b/stellargohorizonclientv300/build/create_account.go @@ -0,0 +1,62 @@ +package build + +import ( + "github.com/stellar/go/amount" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// CreateAccount groups the creation of a new CreateAccountBuilder with a call +// to Mutate. Requires the Destination and NativeAmount mutators to be set. +func CreateAccount(muts ...interface{}) (result CreateAccountBuilder) { + result.Mutate(muts...) + return +} + +// CreateAccountMutator is a interface that wraps the +// MutateCreateAccount operation. types may implement this interface to +// specify how they modify an xdr.PaymentOp object +type CreateAccountMutator interface { + MutateCreateAccount(*xdr.CreateAccountOp) error +} + +// CreateAccountBuilder helps to build CreateAccountOp structs. +// Deprecated use txnbuild.CreateAccount instead +type CreateAccountBuilder struct { + O xdr.Operation + CA xdr.CreateAccountOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *CreateAccountBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case CreateAccountMutator: + err = mut.MutateCreateAccount(&b.CA) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "CreateAccountBuilder error") + return + } + } +} + +// MutateCreateAccount for Destination sets the CreateAccountOp's Destination +// field +func (m Destination) MutateCreateAccount(o *xdr.CreateAccountOp) error { + return setAccountId(m.AddressOrSeed, &o.Destination) +} + +// MutateCreateAccount for NativeAmount sets the CreateAccountOp's +// StartingBalance field +func (m NativeAmount) MutateCreateAccount(o *xdr.CreateAccountOp) (err error) { + o.StartingBalance, err = amount.Parse(m.Amount) + return +} diff --git a/stellargohorizonclientv300/build/create_account_test.go b/stellargohorizonclientv300/build/create_account_test.go new file mode 100644 index 000000000..e57b20906 --- /dev/null +++ b/stellargohorizonclientv300/build/create_account_test.go @@ -0,0 +1,75 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("CreateAccountBuilder Mutators", func() { + + var ( + subject CreateAccountBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = CreateAccountBuilder{} + subject.Mutate(mut) + }) + + Describe("Destination", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = Destination{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.CA.Destination.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = Destination{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("NativeAmount", func() { + BeforeEach(func() { mut = NativeAmount{"101"} }) + It("sets the starting balance properly", func() { + Expect(subject.CA.StartingBalance).To(Equal(xdr.Int64(1010000000))) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/inflation.go b/stellargohorizonclientv300/build/inflation.go new file mode 100644 index 000000000..cb581c9f3 --- /dev/null +++ b/stellargohorizonclientv300/build/inflation.go @@ -0,0 +1,37 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// Inflation groups the creation of a new InflationBuilder with a call to Mutate. +func Inflation(muts ...interface{}) (result InflationBuilder) { + result.Mutate(muts...) + return +} + +// InflationBuilder represents an operation that is being built. +// Deprecated use txnbuild.Inflation instead +type InflationBuilder struct { + O xdr.Operation + Err error +} + +// Mutate applies the provided mutators to this builder's operation. +func (b *InflationBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "InflationBuilder error") + return + } + } +} diff --git a/stellargohorizonclientv300/build/inflation_test.go b/stellargohorizonclientv300/build/inflation_test.go new file mode 100644 index 000000000..1c0990269 --- /dev/null +++ b/stellargohorizonclientv300/build/inflation_test.go @@ -0,0 +1,44 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("InflationBuilder Mutators", func() { + + var ( + subject InflationBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = InflationBuilder{} + subject.Mutate(mut) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/main.go b/stellargohorizonclientv300/build/main.go new file mode 100644 index 000000000..f3e50b2e8 --- /dev/null +++ b/stellargohorizonclientv300/build/main.go @@ -0,0 +1,249 @@ +// Package build implements a builder system for constructing various xdr +// structures used by the stellar network, most importantly transactions. +// +// At the core of this package is the *Builder and *Mutator types. A Builder +// object (ex. PaymentBuilder, TransactionBuilder) contain an underlying xdr +// struct that is being iteratively built by having zero or more Mutator structs +// applied to it. See ExampleTransactionBuilder in main_test.go for an example. +// Deprecated: build package with all its exported methods and variables will no longer be +// maintained. It will be removed in future versions of the SDK. Use txnbuild (https://godoc.org/github.com/stellar/go/txnbuild) instead. +package build + +import ( + "math" + + "github.com/stellar/go/amount" + "github.com/stellar/go/network" + "github.com/stellar/go/xdr" +) + +const ( + // MemoTextMaxLength represents the maximum number of bytes a valid memo of + // type "MEMO_TEXT" can be. + MemoTextMaxLength = 28 +) + +var ( + // PublicNetwork is a mutator that configures the transaction for submission + // to the main public stellar network. + PublicNetwork = Network{network.PublicNetworkPassphrase} + + // TestNetwork is a mutator that configures the transaction for submission + // to the test stellar network (often called testnet). + TestNetwork = Network{network.TestNetworkPassphrase} + + // DefaultNetwork is a mutator that configures the + // transaction for submission to the default stellar + // network. Integrators may change this value to + // another `Network` mutator if they would like to + // effect the default in a process-global manner. + // Replace or set your own custom passphrase on this + // var to set the default network for the process. + DefaultNetwork = Network{} +) + +// Amount is a mutator capable of setting the amount +type Amount string + +// Asset is struct used in path_payment mutators +type Asset struct { + Code string + Issuer string + Native bool +} + +// AllowTrustAsset is a mutator capable of setting the asset on +// an operations that have one. +type AllowTrustAsset struct { + Code string +} + +// Authorize is a mutator capable of setting the `authorize` flag +type Authorize struct { + Value uint32 +} + +// AutoSequence loads the sequence to use for the transaction from an external +// provider. +type AutoSequence struct { + SequenceProvider +} + +// BumpTo sets sequence number on BumpSequence operation +type BumpTo int64 + +// NativeAsset is a helper method to create native Asset object +func NativeAsset() Asset { + return Asset{Native: true} +} + +// CreditAsset is a helper method to create credit Asset object +func CreditAsset(code, issuer string) Asset { + return Asset{code, issuer, false} +} + +// CreditAmount is a mutator that configures a payment to be using credit +// asset and have the amount provided. +type CreditAmount struct { + Code string + Issuer string + Amount string +} + +// Defaults is a mutator that sets defaults +type Defaults struct{} + +// Destination is a mutator capable of setting the destination on +// an operations that have one. +type Destination struct { + AddressOrSeed string +} + +// InflationDest is a mutator capable of setting the inflation destination +type InflationDest string + +// HomeDomain is a mutator capable of setting home domain of the account +type HomeDomain string + +// MemoHash is a mutator that sets a memo on the mutated transaction of type +// MEMO_HASH. +type MemoHash struct { + Value xdr.Hash +} + +// Limit is a mutator that sets a limit on the change_trust operation +type Limit Amount + +// MasterWeight is a mutator that sets account's master weight +type MasterWeight uint32 + +// MaxLimit represents the maximum value that can be passed as trutline Limit +var MaxLimit = Limit(amount.String(math.MaxInt64)) + +// MemoID is a mutator that sets a memo on the mutated transaction of type +// MEMO_ID. +type MemoID struct { + Value uint64 +} + +// MemoReturn is a mutator that sets a memo on the mutated transaction of type +// MEMO_RETURN. +type MemoReturn struct { + Value xdr.Hash +} + +// MemoText is a mutator that sets a memo on the mutated transaction of type +// MEMO_TEXT. +type MemoText struct { + Value string +} + +// NativeAmount is a mutator that configures a payment to be using native +// currency and have the amount provided (in lumens). +type NativeAmount struct { + Amount string +} + +// OfferID is a mutator that sets offer ID on offer operations +type OfferID uint64 + +// PayWithPath is a mutator that configures a path_payment's send asset and max amount +type PayWithPath struct { + Asset + MaxAmount string + Path []Asset +} + +// Through appends a new asset to the path +func (pathSend PayWithPath) Through(asset Asset) PayWithPath { + pathSend.Path = append(pathSend.Path, asset) + return pathSend +} + +// PayWith is a helper to create PayWithPath struct +func PayWith(sendAsset Asset, maxAmount string) PayWithPath { + return PayWithPath{ + Asset: sendAsset, + MaxAmount: maxAmount, + } +} + +// Price is a mutator that sets price on offer operations +type Price string + +// Rate is a mutator that sets selling/buying asset and price on offer operations +type Rate struct { + Selling Asset + Buying Asset + Price +} + +// Sequence is a mutator that sets the sequence number on a transaction +type Sequence struct { + Sequence uint64 +} + +// SequenceProvider is the interface that other packages may implement to be +// used with the `AutoSequence` mutator. +type SequenceProvider interface { + SequenceForAccount(aid string) (xdr.SequenceNumber, error) +} + +// Sign is a mutator that contributes a signature of the provided envelope's +// transaction with the configured key +type Sign struct { + Seed string +} + +// SetFlag is a mutator capable of setting account flags +type SetFlag int32 + +// ClearFlag is a mutator capable of clearing account flags +type ClearFlag int32 + +// Signer is a mutator capable of adding, updating and deleting an account +// signer +type Signer struct { + Address string + Weight uint32 +} + +// SourceAccount is a mutator capable of setting the source account on +// an xdr.Operation and an xdr.Transaction +type SourceAccount struct { + AddressOrSeed string +} + +// Thresholds is a mutator capable of setting account thresholds +type Thresholds struct { + Low *uint32 + Medium *uint32 + High *uint32 +} + +type Timebounds struct { + MinTime uint64 + MaxTime uint64 +} + +// Trustor is a mutator capable of setting the trustor on +// allow_trust operation. +type Trustor struct { + Address string +} + +// Network establishes the stellar network that a transaction should apply to. +// This modifier influences how a transaction is hashed for the purposes of signature generation. +type Network struct { + Passphrase string +} + +// ID returns the network ID derived from this struct's Passphrase +func (n *Network) ID() [32]byte { + return network.ID(n.Passphrase) +} + +// BaseFee is a mutator capable of setting the base fee +type BaseFee struct { + Amount uint64 +} diff --git a/stellargohorizonclientv300/build/main_test.go b/stellargohorizonclientv300/build/main_test.go new file mode 100644 index 000000000..514675c08 --- /dev/null +++ b/stellargohorizonclientv300/build/main_test.go @@ -0,0 +1,540 @@ +package build + +import ( + "fmt" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestBuild(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Package: github.com/stellar/go/build") +} + +// ExampleTransactionBuilder creates and signs a simple transaction, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +// +// It uses the transaction builder system +func ExampleTransactionBuilder() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Payment( + Destination{"GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"}, + NativeAmount{"50"}, + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAAAAAAB3NZQAAAAAAAAAAARtDMfAAAABA2oIeQxoJl53RMRWFeLB865zcky39f2gf2PmUubCuJYccEePRSrTC8QQrMOgGwD8a6oe8dgltvezdDsmmXBPyBw== +} + +// ExampleCreateAccount creates a transaction to fund a new stallar account with a balance. It then +// encodes the transaction into a base64 string capable of being submitted to stellar-core. It uses +// the transaction builder system. +func ExampleCreateAccount() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + CreateAccount( + Destination{"GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"}, + NativeAmount{"50"}, + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAHc1lAAAAAAAAAAABG0Mx8AAAAEDiHQEurLITX87zmkEi8Rrcf5wGp1JrLnSDoTJiN+yNjJZVF3WcBJgoGyIJ3NJo+tNmTqALVrJziiiZGdoukxcN +} + +// ExampleBumpSequence creates a transaction to bump sequence of a given account. It then +// encodes the transaction into a base64 string capable of being submitted to stellar-core. It uses +// the transaction builder system. +func ExampleBumpSequence() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + BumpSequence( + BumpTo(5), + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAsAAAAAAAAABQAAAAAAAAABG0Mx8AAAAEAZkMhF/4tin/eiAw+yj13iQ9xApg0wadSyIMdk2D73RvwvgxwqfAGF6qmL1d8qqrjClZ7Vi0MYBDPxOQchwMQA +} + +// ExamplePayment creates and signs a native-asset Payment, encodes it into a base64 string capable of +// being submitted to stellar-core. It uses the transaction builder system. +func ExamplePayment() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Payment( + Destination{"GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"}, + NativeAmount{"50"}, + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAAAAAAB3NZQAAAAAAAAAAARtDMfAAAABA2oIeQxoJl53RMRWFeLB865zcky39f2gf2PmUubCuJYccEePRSrTC8QQrMOgGwD8a6oe8dgltvezdDsmmXBPyBw== +} + +// ExamplePathPayment creates and signs a simple transaction with PathPayment operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExamplePathPayment() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Payment( + Destination{"GBDT3K42LOPSHNAEHEJ6AVPADIJ4MAR64QEKKW2LQPBSKLYD22KUEH4P"}, + CreditAmount{"USD", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA", "50"}, + PayWith(CreditAsset("EUR", "GCPZJ3MJQ3GUGJSBL6R3MLYZS6FKVHG67BPAINMXL3NWNXR5S6XG657P"), "100"). + Through(Asset{Native: true}). + Through(CreditAsset("BTC", "GAHJZHVKFLATAATJH46C7OK2ZOVRD47GZBGQ7P6OCVF6RJDCEG5JMQBQ")), + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAIAAAABRVVSAAAAAACflO2Jhs1DJkFfo7YvGZeKqpze+F4ENZde22bePZeubwAAAAA7msoAAAAAAEc9q5pbnyO0BDkT4FXgGhPGAj7kCKVbS4PDJS8D1pVCAAAAAVVTRAAAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAHc1lAAAAAAIAAAAAAAAAAUJUQwAAAAAADpyeqirBMAJpPzwvuVrLqxHz5shND7/OFUvopGIhupYAAAAAAAAAARtDMfAAAABA5xuIJu/KGKQRuDrdkzNsR4HjT6wX464SHZ/yvYwVb/AkAyyfeMLDNhgKbBxQMWc3Uo5fTst1UHldC+jYNeAhCQ== +} + +// ExampleSetOptions creates and signs a simple transaction with SetOptions operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleSetOptions() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + SetOptions( + InflationDest("GCT7S5BA6ZC7SV7GGEMEYJTWOBYTBOA7SC4JEYP7IAEDG7HQNIWKRJ4G"), + SetAuthRequired(), + SetAuthRevocable(), + SetAuthImmutable(), + ClearAuthRequired(), + ClearAuthRevocable(), + ClearAuthImmutable(), + MasterWeight(1), + SetThresholds(2, 3, 4), + HomeDomain("stellar.org"), + AddSigner("GC6DDGPXVWXD5V6XOWJ7VUTDYI7VKPV2RAJWBVBHR47OPV5NASUNHTJW", 5), + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAUAAAABAAAAAKf5dCD2RflX5jEYTCZ2cHEwuB+QuJJh/0AIM3zwaiyoAAAAAQAAAAcAAAABAAAABwAAAAEAAAABAAAAAQAAAAIAAAABAAAAAwAAAAEAAAAEAAAAAQAAAAtzdGVsbGFyLm9yZwAAAAABAAAAALwxmfetrj7X13WT+tJjwj9VPrqIE2DUJ48+59etBKjTAAAABQAAAAAAAAABG0Mx8AAAAECZF17pOfZcyc7YJXMyx++PMydIvL6g2yZcPDY8h4+tmlz+3rsE6uuX0R6xfgNnuMntvK4YMmaOvp4DvaZMMNoA +} + +// ExampleSetOptions_manyOperations creates and signs a simple transaction with many SetOptions operations, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleSetOptions_manyOperations() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + InflationDest("GCT7S5BA6ZC7SV7GGEMEYJTWOBYTBOA7SC4JEYP7IAEDG7HQNIWKRJ4G"), + SetAuthRequired(), + SetAuthRevocable(), + SetAuthImmutable(), + ClearAuthRequired(), + ClearAuthRevocable(), + ClearAuthImmutable(), + MasterWeight(1), + SetThresholds(2, 3, 4), + HomeDomain("stellar.org"), + RemoveSigner("GC6DDGPXVWXD5V6XOWJ7VUTDYI7VKPV2RAJWBVBHR47OPV5NASUNHTJW"), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAETAAAAAAAAAABAAAAAAAAAAAAAAALAAAAAAAAAAUAAAABAAAAAKf5dCD2RflX5jEYTCZ2cHEwuB+QuJJh/0AIM3zwaiyoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAQAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAABAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAEAAAADAAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAALc3RlbGxhci5vcmcAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAALwxmfetrj7X13WT+tJjwj9VPrqIE2DUJ48+59etBKjTAAAAAAAAAAAAAAABG0Mx8AAAAEAOXsLbFo3e8fpqyeZEHGP9o/IrQDQRyof+DA1EeUkvUGbNhy57xXcpMhZpRtwXThWBYx4za4q+TRrnoZQtezgN +} + +// ExampleChangeTrust creates and signs a simple transaction with ChangeTrust operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleChangeTrust() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Trust("USD", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA", Limit("100.25")), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABVVNEAAAAAAAtJGku0Iu/Z5uhmUSIcNIZHodv7Nkv3Z9tJ02k5t4TQQAAAAA7wO+gAAAAAAAAAAEbQzHwAAAAQOIy19X38Y3jcFzvhDsmXu6iDzrzb4iwfS2NAq9GGAFiRJUGoFX85vKtlNcXzQppF4X8oIMNPEb74fuZE/N+GAE= +} + +// ExampleChangeTrust_maxLimit creates and signs a simple transaction with ChangeTrust operation (maximum limit), and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleChangeTrust_maxLimit() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Trust("USD", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABVVNEAAAAAAAtJGku0Iu/Z5uhmUSIcNIZHodv7Nkv3Z9tJ02k5t4TQX//////////AAAAAAAAAAEbQzHwAAAAQJQC6R3RqNaw5rOmaxqpAE0lD5onM/njn9I2RVlhtS2SGi2Z7xm65USYVWXTJFVqTCfTwwu+QXFcOuqgJjVtHAk= +} + +// ExampleRemoveTrust creates and signs a simple transaction with ChangeTrust operation (remove trust), and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleRemoveTrust() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + operationSource := "GCVJCNUHSGKOTBBSXZJ7JJZNOSE2YDNGRLIDPMQDUEQWJQSE6QZSDPNU" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + RemoveTrust( + "USD", + "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA", + SourceAccount{operationSource}, + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAQAAAACqkTaHkZTphDK+U/SnLXSJrA2mitA3sgOhIWTCRPQzIQAAAAYAAAABVVNEAAAAAAAtJGku0Iu/Z5uhmUSIcNIZHodv7Nkv3Z9tJ02k5t4TQQAAAAAAAAAAAAAAAAAAAAEbQzHwAAAAQD5FeGBEwJyeauK+WKfcxYBeKw62EtCqvC0p9Z+1cY32fKQ+5Jz9uE1LaDsHW5NurtStKcUTiG5j2qNDf1QpYgw= +} + +// ExampleManageOffer creates and signs a simple transaction with ManageOffer operations, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleManageOffer() { + rate := Rate{ + Selling: NativeAsset(), + Buying: CreditAsset("USD", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"), + Price: Price("125.12"), + } + + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + CreateOffer(rate, "20"), + UpdateOffer(rate, "40", OfferID(2)), + DeleteOffer(rate, OfferID(1)), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAABLAAAAAAAAAABAAAAAAAAAAAAAAADAAAAAAAAAAMAAAAAAAAAAVVTRAAAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAC+vCAAAADDgAAAAZAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAABVVNEAAAAAAAtJGku0Iu/Z5uhmUSIcNIZHodv7Nkv3Z9tJ02k5t4TQQAAAAAX14QAAAAMOAAAABkAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAFVU0QAAAAAAC0kaS7Qi79nm6GZRIhw0hkeh2/s2S/dn20nTaTm3hNBAAAAAAAAAAAAAAw4AAAAGQAAAAAAAAABAAAAAAAAAAEbQzHwAAAAQBfosk+t8qpULHP4ppNX2xVPih8lmnbHFZdeuxSP6pgpCCX05S7zZ4PsjVQY2nOnLru6mBTc1r8So+vxHs3FXAc= +} + +// ExampleCreatePassiveOffer creates and signs a simple transaction with CreatePassiveOffer operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleCreatePassiveOffer() { + rate := Rate{ + Selling: NativeAsset(), + Buying: CreditAsset("USD", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"), + Price: Price("125.12"), + } + + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + CreatePassiveOffer(rate, "20"), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAQAAAAAAAAAAVVTRAAAAAAALSRpLtCLv2eboZlEiHDSGR6Hb+zZL92fbSdNpObeE0EAAAAAC+vCAAAADDgAAAAZAAAAAAAAAAEbQzHwAAAAQHv/1xLn+ArfIUoWjn3V0zVka6tulqMYx4zJZhGqdmTw8iCXY0ZtHS+y+7YGgR3vM1DpKOdvWTmhee+sCXIppQA= +} + +// ExampleAccountMerge creates and signs a simple transaction with AccountMerge operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleAccountMerge() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + AccountMerge( + Destination{"GBDT3K42LOPSHNAEHEJ6AVPADIJ4MAR64QEKKW2LQPBSKLYD22KUEH4P"}, + ), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAgAAAAARz2rmlufI7QEORPgVeAaE8YCPuQIpVtLg8MlLwPWlUIAAAAAAAAAARtDMfAAAABAh3qZrP5T9Xg0LdzwOLx/eA/B7bzj+8j+s9eXNuu7/Ldch7I6kW5iYz6Vfy32FVnKNtoykToB7nQY2o2vo1tqAw== +} + +// ExampleInflation creates and signs a simple transaction with Inflation operation, and then +// encodes it into a base64 string capable of being submitted to stellar-core. +func ExampleInflation() { + seed := "SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H" + tx, err := Transaction( + SourceAccount{seed}, + Sequence{1}, + TestNetwork, + Inflation(), + ) + + if err != nil { + fmt.Println(err) + return + } + + txe, err := tx.Sign(seed) + if err != nil { + fmt.Println(err) + return + } + + txeB64, err := txe.Base64() + + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("tx base64: %s", txeB64) + // Output: tx base64: AAAAADZY/nWY0gx6beMpf4S8Ur0qHsjA8fbFtBzBx1cbQzHwAAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAkAAAAAAAAAARtDMfAAAABAzzDG4V7KzynWY0ER/V4HH0WgDvl3hrIizDcKW3qEQY4Ib3yXufVvdbzsET/Dj5js5dgDkcYgikHwRCpqi/J8BQ== +} diff --git a/stellargohorizonclientv300/build/manage_data.go b/stellargohorizonclientv300/build/manage_data.go new file mode 100644 index 000000000..f29b8628f --- /dev/null +++ b/stellargohorizonclientv300/build/manage_data.go @@ -0,0 +1,75 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// ClearData removes a key/value pair associated with the source account +func ClearData(name string, muts ...interface{}) (result ManageDataBuilder) { + result.MD.DataName = xdr.String64(name) + result.MD.DataValue = nil + result.validateName() + result.Mutate(muts...) + return +} + +// SetData sets a key/value pair associated with the source account, updating it +// if one already exists. +func SetData(name string, value []byte, muts ...interface{}) (result ManageDataBuilder) { + result.MD.DataName = xdr.String64(name) + v := xdr.DataValue(value) + result.MD.DataValue = &v + result.validateName() + result.validateValue() + result.Mutate(muts...) + return +} + +// ManageDataBuilder helps to build ManageDataOp structs. +// Deprecated use txnbuild.ManageData instead +type ManageDataBuilder struct { + O xdr.Operation + MD xdr.ManageDataOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *ManageDataBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "ManageDataBuilder error") + return + } + } +} + +func (b *ManageDataBuilder) validateName() { + if len(b.MD.DataName) > 64 { + b.Err = errors.New("Name too long: must be less than 64 bytes") + return + } + + if b.MD.DataName == "" { + b.Err = errors.New("Invalid name: empty string") + return + } +} + +func (b *ManageDataBuilder) validateValue() { + if *b.MD.DataValue == nil { + b.Err = errors.New("Invalid value: cannot set a nil value") + } + + if len(*b.MD.DataValue) > 64 { + b.Err = errors.New("Value too long: must be less than 64 bytes") + } +} diff --git a/stellargohorizonclientv300/build/manage_data_test.go b/stellargohorizonclientv300/build/manage_data_test.go new file mode 100644 index 000000000..04161d954 --- /dev/null +++ b/stellargohorizonclientv300/build/manage_data_test.go @@ -0,0 +1,166 @@ +package build + +import ( + "strings" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("ClearData", func() { + var ( + subject ManageDataBuilder + name string + ) + + JustBeforeEach(func() { + subject = ClearData(name) + }) + + Context("Valid name", func() { + BeforeEach(func() { + name = "my data" + }) + + It("succeeds", func() { + Expect(subject.Err).ToNot(HaveOccurred()) + Expect(subject.MD.DataName).To(Equal(xdr.String64("my data"))) + Expect(subject.MD.DataValue).To(BeNil()) + }) + }) + + Context("Long key", func() { + BeforeEach(func() { name = strings.Repeat("a", 65) }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("empty key", func() { + BeforeEach(func() { name = "" }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) +}) + +var _ = Describe("SetData", func() { + var ( + subject ManageDataBuilder + name string + value []byte + ) + + JustBeforeEach(func() { + subject = SetData(name, value) + }) + + Context("Valid name and value", func() { + BeforeEach(func() { + name = "my data" + value = []byte{0xFF, 0xFF} + }) + + It("succeeds", func() { + Expect(subject.Err).ToNot(HaveOccurred()) + Expect(subject.MD.DataName).To(Equal(xdr.String64("my data"))) + Expect(*subject.MD.DataValue).To(Equal(xdr.DataValue([]byte{0xFF, 0xFF}))) + }) + }) + + Context("empty value", func() { + BeforeEach(func() { + name = "some name" + value = []byte{} + }) + + It("succeeds", func() { + Expect(subject.Err).ToNot(HaveOccurred()) + Expect(subject.MD.DataName).To(Equal(xdr.String64("some name"))) + }) + }) + + Context("Long key", func() { + BeforeEach(func() { + name = strings.Repeat("a", 65) + value = []byte{} + }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("empty key", func() { + BeforeEach(func() { + name = "" + value = []byte{} + }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("nil value", func() { + BeforeEach(func() { + name = "some name" + value = nil + }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("Long value", func() { + BeforeEach(func() { + name = "some name" + value = []byte(strings.Repeat("a", 65)) + }) + + It("errors", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) +}) + +var _ = Describe("ManageData Mutators", func() { + + var ( + subject ManageDataBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = ManageDataBuilder{} + subject.Mutate(mut) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/manage_offer.go b/stellargohorizonclientv300/build/manage_offer.go new file mode 100644 index 000000000..9d3d7195d --- /dev/null +++ b/stellargohorizonclientv300/build/manage_offer.go @@ -0,0 +1,133 @@ +package build + +import ( + "github.com/stellar/go/amount" + "github.com/stellar/go/price" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// CreateOffer creates a new offer +func CreateOffer(rate Rate, amount Amount) (result ManageOfferBuilder) { + return ManageOffer(false, rate, amount) +} + +// CreatePassiveOffer creates a new passive offer +func CreatePassiveOffer(rate Rate, amount Amount) (result ManageOfferBuilder) { + return ManageOffer(true, rate, amount) +} + +// UpdateOffer updates an existing offer +func UpdateOffer(rate Rate, amount Amount, offerID OfferID) (result ManageOfferBuilder) { + return ManageOffer(false, rate, amount, offerID) +} + +// DeleteOffer deletes an existing offer +func DeleteOffer(rate Rate, offerID OfferID) (result ManageOfferBuilder) { + return ManageOffer(false, rate, Amount("0"), offerID) +} + +// ManageOffer groups the creation of a new ManageOfferBuilder with a call to Mutate. +func ManageOffer(passiveOffer bool, muts ...interface{}) (result ManageOfferBuilder) { + result.PassiveOffer = passiveOffer + result.Mutate(muts...) + return +} + +// ManageOfferMutator is a interface that wraps the +// MutateManageOffer operation. types may implement this interface to +// specify how they modify an xdr.ManageOfferOp object +type ManageOfferMutator interface { + MutateManageOffer(interface{}) error +} + +// ManageOfferBuilder represents a transaction that is being built. +// Deprecated use txnbuild.ManageSellOffer instead +type ManageOfferBuilder struct { + PassiveOffer bool + O xdr.Operation + MO xdr.ManageSellOfferOp + PO xdr.CreatePassiveSellOfferOp + Err error +} + +// Mutate applies the provided mutators to this builder's offer or operation. +func (b *ManageOfferBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case ManageOfferMutator: + if b.PassiveOffer { + err = mut.MutateManageOffer(&b.PO) + } else { + err = mut.MutateManageOffer(&b.MO) + } + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "ManageOfferBuilder error") + return + } + } +} + +// MutateManageOffer for Amount sets the ManageOfferOp's Amount field +func (m Amount) MutateManageOffer(o interface{}) (err error) { + switch o := o.(type) { + default: + err = errors.New("Unexpected operation type") + case *xdr.ManageSellOfferOp: + o.Amount, err = amount.Parse(string(m)) + case *xdr.CreatePassiveSellOfferOp: + o.Amount, err = amount.Parse(string(m)) + } + return +} + +// MutateManageOffer for OfferID sets the ManageOfferOp's OfferID field +func (m OfferID) MutateManageOffer(o interface{}) (err error) { + switch o := o.(type) { + default: + err = errors.New("Unexpected operation type") + case *xdr.ManageSellOfferOp: + o.OfferId = xdr.Int64(m) + } + return +} + +// MutateManageOffer for Rate sets the ManageOfferOp's selling, buying and price fields +func (m Rate) MutateManageOffer(o interface{}) (err error) { + switch o := o.(type) { + default: + err = errors.New("Unexpected operation type") + case *xdr.ManageSellOfferOp: + o.Selling, err = m.Selling.ToXDR() + if err != nil { + return + } + + o.Buying, err = m.Buying.ToXDR() + if err != nil { + return + } + + o.Price, err = price.Parse(string(m.Price)) + case *xdr.CreatePassiveSellOfferOp: + o.Selling, err = m.Selling.ToXDR() + if err != nil { + return + } + + o.Buying, err = m.Buying.ToXDR() + if err != nil { + return + } + + o.Price, err = price.Parse(string(m.Price)) + } + return +} diff --git a/stellargohorizonclientv300/build/manage_offer_test.go b/stellargohorizonclientv300/build/manage_offer_test.go new file mode 100644 index 000000000..f4c3abd89 --- /dev/null +++ b/stellargohorizonclientv300/build/manage_offer_test.go @@ -0,0 +1,172 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("ManageOffer", func() { + + Describe("ManageOfferBuilder", func() { + var ( + subject ManageOfferBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + + rate = Rate{ + Selling: CreditAsset("EUR", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"), + Buying: NativeAsset(), + Price: Price("41.265"), + } + ) + + JustBeforeEach(func() { + subject = ManageOfferBuilder{} + subject.Mutate(mut) + }) + + Describe("CreateOffer", func() { + Context("creates offer properly", func() { + It("sets values properly", func() { + builder := CreateOffer(rate, "20") + + Expect(builder.MO.Amount).To(Equal(xdr.Int64(200000000))) + + Expect(builder.MO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(builder.MO.Selling.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'E', 'U', 'R', 0})) + var aid xdr.AccountId + aid.SetAddress(rate.Selling.Issuer) + Expect(builder.MO.Selling.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(builder.MO.Selling.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Buying.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(builder.MO.Buying.AlphaNum4).To(BeNil()) + Expect(builder.MO.Buying.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Price.N).To(Equal(xdr.Int32(8253))) + Expect(builder.MO.Price.D).To(Equal(xdr.Int32(200))) + + Expect(builder.MO.OfferId).To(Equal(xdr.Int64(0))) + }) + }) + }) + + Describe("UpdateOffer", func() { + Context("updates the offer properly", func() { + It("sets values properly", func() { + builder := UpdateOffer(rate, "100", 5) + + Expect(builder.MO.Amount).To(Equal(xdr.Int64(1000000000))) + + Expect(builder.MO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(builder.MO.Selling.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'E', 'U', 'R', 0})) + var aid xdr.AccountId + aid.SetAddress(rate.Selling.Issuer) + Expect(builder.MO.Selling.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(builder.MO.Selling.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Buying.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(builder.MO.Buying.AlphaNum4).To(BeNil()) + Expect(builder.MO.Buying.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Price.N).To(Equal(xdr.Int32(8253))) + Expect(builder.MO.Price.D).To(Equal(xdr.Int32(200))) + + Expect(builder.MO.OfferId).To(Equal(xdr.Int64(5))) + }) + }) + }) + + Describe("DeleteOffer", func() { + Context("deletes the offer properly", func() { + It("sets values properly", func() { + builder := DeleteOffer(rate, 10) + + Expect(builder.MO.Amount).To(Equal(xdr.Int64(0))) + + Expect(builder.MO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(builder.MO.Selling.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'E', 'U', 'R', 0})) + var aid xdr.AccountId + aid.SetAddress(rate.Selling.Issuer) + Expect(builder.MO.Selling.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(builder.MO.Selling.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Buying.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(builder.MO.Buying.AlphaNum4).To(BeNil()) + Expect(builder.MO.Buying.AlphaNum12).To(BeNil()) + + Expect(builder.MO.Price.N).To(Equal(xdr.Int32(8253))) + Expect(builder.MO.Price.D).To(Equal(xdr.Int32(200))) + + Expect(builder.MO.OfferId).To(Equal(xdr.Int64(10))) + }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + }) + + Describe("CreatePassiveOfferBuilder", func() { + var ( + subject ManageOfferBuilder + mut interface{} + + rate = Rate{ + Selling: CreditAsset("EUR", "GAWSI2JO2CF36Z43UGMUJCDQ2IMR5B3P5TMS7XM7NUTU3JHG3YJUDQXA"), + Buying: NativeAsset(), + Price: Price("41.265"), + } + ) + + JustBeforeEach(func() { + subject = ManageOfferBuilder{} + subject.Mutate(mut) + }) + + Describe("CreatePassiveOffer", func() { + Context("creates offer properly", func() { + It("sets values properly", func() { + builder := CreatePassiveOffer(rate, "20") + + Expect(builder.PO.Amount).To(Equal(xdr.Int64(200000000))) + + Expect(builder.PO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(builder.PO.Selling.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'E', 'U', 'R', 0})) + var aid xdr.AccountId + aid.SetAddress(rate.Selling.Issuer) + Expect(builder.PO.Selling.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(builder.PO.Selling.AlphaNum12).To(BeNil()) + + Expect(builder.PO.Buying.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(builder.PO.Buying.AlphaNum4).To(BeNil()) + Expect(builder.PO.Buying.AlphaNum12).To(BeNil()) + + Expect(builder.PO.Price.N).To(Equal(xdr.Int32(8253))) + Expect(builder.PO.Price.D).To(Equal(xdr.Int32(200))) + }) + }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/operation.go b/stellargohorizonclientv300/build/operation.go new file mode 100644 index 000000000..7a7bfe401 --- /dev/null +++ b/stellargohorizonclientv300/build/operation.go @@ -0,0 +1,19 @@ +package build + +import ( + "github.com/stellar/go/xdr" +) + +// OperationMutator is a interface that wraps the MutateOperation operation. +// types may implement this interface to specify how they modify an +// xdr.Operation object +type OperationMutator interface { + MutateOperation(*xdr.Operation) error +} + +// MutateOperation for SourceAccount sets the operation's SourceAccount +// to the pubilic key for the address provided +func (m SourceAccount) MutateOperation(o *xdr.Operation) error { + o.SourceAccount = &xdr.MuxedAccount{} + return setMuxedAccount(m.AddressOrSeed, o.SourceAccount) +} diff --git a/stellargohorizonclientv300/build/payment.go b/stellargohorizonclientv300/build/payment.go new file mode 100644 index 000000000..26c8e6b08 --- /dev/null +++ b/stellargohorizonclientv300/build/payment.go @@ -0,0 +1,156 @@ +package build + +import ( + "github.com/stellar/go/amount" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// Payment groups the creation of a new PaymentBuilder with a call to Mutate. +// Requires the Destination and NativeAmount mutators to be set. +func Payment(muts ...interface{}) (result PaymentBuilder) { + result.Mutate(muts...) + return +} + +// PaymentMutator is a interface that wraps the +// MutatePayment operation. types may implement this interface to +// specify how they modify an xdr.PaymentOp object +type PaymentMutator interface { + MutatePayment(interface{}) error +} + +// PaymentBuilder represents a transaction that is being built. +// Deprecated use txnbuild.Payment instead +type PaymentBuilder struct { + PathPayment bool + O xdr.Operation + P xdr.PaymentOp + PP xdr.PathPaymentStrictReceiveOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *PaymentBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + if _, ok := m.(PayWithPath); ok { + b.PathPayment = true + break + } + } + + for _, m := range muts { + var err error + switch mut := m.(type) { + case PaymentMutator: + if b.PathPayment { + err = mut.MutatePayment(&b.PP) + } else { + err = mut.MutatePayment(&b.P) + } + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "PaymentBuilder error") + return + } + } +} + +// MutatePayment for Asset sets the PaymentOp's Asset field +func (m CreditAmount) MutatePayment(o interface{}) (err error) { + switch o := o.(type) { + default: + err = errors.New("Unexpected operation type") + case *xdr.PaymentOp: + o.Amount, err = amount.Parse(m.Amount) + if err != nil { + return + } + + o.Asset, err = createAlphaNumAsset(m.Code, m.Issuer) + case *xdr.PathPaymentStrictReceiveOp: + o.DestAmount, err = amount.Parse(m.Amount) + if err != nil { + return + } + + o.DestAsset, err = createAlphaNumAsset(m.Code, m.Issuer) + } + return +} + +// MutatePayment for Destination sets the PaymentOp's Destination field +func (m Destination) MutatePayment(o interface{}) error { + switch o := o.(type) { + default: + return errors.New("Unexpected operation type") + case *xdr.PaymentOp: + return setMuxedAccount(m.AddressOrSeed, &o.Destination) + case *xdr.PathPaymentStrictReceiveOp: + return setMuxedAccount(m.AddressOrSeed, &o.Destination) + } +} + +// MutatePayment for NativeAmount sets the PaymentOp's currency field to +// native and sets its amount to the provided integer +func (m NativeAmount) MutatePayment(o interface{}) (err error) { + switch o := o.(type) { + default: + err = errors.New("Unexpected operation type") + case *xdr.PaymentOp: + o.Amount, err = amount.Parse(m.Amount) + if err != nil { + return + } + + o.Asset, err = xdr.NewAsset(xdr.AssetTypeAssetTypeNative, nil) + case *xdr.PathPaymentStrictReceiveOp: + o.DestAmount, err = amount.Parse(m.Amount) + if err != nil { + return + } + + o.DestAsset, err = xdr.NewAsset(xdr.AssetTypeAssetTypeNative, nil) + } + return +} + +// MutatePayment for PayWithPath sets the PathPaymentOp's SendAsset, +// SendMax and Path fields +func (m PayWithPath) MutatePayment(o interface{}) (err error) { + var pathPaymentOp *xdr.PathPaymentStrictReceiveOp + var ok bool + if pathPaymentOp, ok = o.(*xdr.PathPaymentStrictReceiveOp); !ok { + return errors.New("Unexpected operation type") + } + + // MaxAmount + pathPaymentOp.SendMax, err = amount.Parse(m.MaxAmount) + if err != nil { + return + } + + // Path + var path []xdr.Asset + var xdrAsset xdr.Asset + + for _, asset := range m.Path { + xdrAsset, err = asset.ToXDR() + if err != nil { + return err + } + + path = append(path, xdrAsset) + } + + pathPaymentOp.Path = path + + // Asset + pathPaymentOp.SendAsset, err = m.Asset.ToXDR() + return +} diff --git a/stellargohorizonclientv300/build/payment_test.go b/stellargohorizonclientv300/build/payment_test.go new file mode 100644 index 000000000..1c0d2fcce --- /dev/null +++ b/stellargohorizonclientv300/build/payment_test.go @@ -0,0 +1,284 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("Payment Mutators", func() { + + var ( + subject PaymentBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + Describe("Payment", func() { + JustBeforeEach(func() { + subject = PaymentBuilder{} + subject.Mutate(mut) + }) + + Describe("CreditAmount", func() { + Context("AlphaNum4", func() { + BeforeEach(func() { + mut = CreditAmount{"USD", address, "50.0"} + }) + It("sets the asset properly", func() { + Expect(subject.P.Amount).To(Equal(xdr.Int64(500000000))) + Expect(subject.P.Asset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(subject.P.Asset.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'U', 'S', 'D', 0})) + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.P.Asset.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(subject.P.Asset.AlphaNum12).To(BeNil()) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + + Context("AlphaNum12", func() { + BeforeEach(func() { + mut = CreditAmount{"ABCDEF", address, "50.0"} + }) + It("sets the asset properly", func() { + Expect(subject.P.Amount).To(Equal(xdr.Int64(500000000))) + Expect(subject.P.Asset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum12)) + Expect(subject.P.Asset.AlphaNum4).To(BeNil()) + Expect(subject.P.Asset.AlphaNum12.AssetCode).To(Equal(xdr.AssetCode12{'A', 'B', 'C', 'D', 'E', 'F', 0, 0, 0, 0, 0, 0})) + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.P.Asset.AlphaNum12.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + + Context("issuer invalid", func() { + BeforeEach(func() { + mut = CreditAmount{"USD", bad, "50.0"} + }) + + It("failed", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("amount invalid", func() { + BeforeEach(func() { + mut = CreditAmount{"ABCDEF", address, "test"} + }) + + It("failed", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("asset code length invalid", func() { + Context("empty", func() { + BeforeEach(func() { + mut = CreditAmount{"", address, "50.0"} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + + Context("too long", func() { + BeforeEach(func() { + mut = CreditAmount{"1234567890123", address, "50.0"} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + }) + }) + + Describe("Destination", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = Destination{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.P.Destination.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = Destination{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("NativeAmount", func() { + BeforeEach(func() { mut = NativeAmount{"101"} }) + It("sets the starting balance properly", func() { + Expect(subject.P.Asset.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(subject.P.Amount).To(Equal(xdr.Int64(1010000000))) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + }) + + Describe("PathPayment", func() { + JustBeforeEach(func() { + subject = PaymentBuilder{} + subject.Mutate(PayWith(CreditAsset("EUR", "GCPZJ3MJQ3GUGJSBL6R3MLYZS6FKVHG67BPAINMXL3NWNXR5S6XG657P"), "100"). + Through(NativeAsset()). + Through(CreditAsset("BTC", "GAHJZHVKFLATAATJH46C7OK2ZOVRD47GZBGQ7P6OCVF6RJDCEG5JMQBQ"))) + subject.Mutate(mut) + }) + + Describe("Destination", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = Destination{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.PP.Destination.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = Destination{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("Destination: Asset and Amount", func() { + Context("native", func() { + BeforeEach(func() { + mut = NativeAmount{"50"} + }) + It("sets the fields properly", func() { + Expect(subject.PP.DestAmount).To(Equal(xdr.Int64(500000000))) + Expect(subject.PP.DestAsset.Type).To(Equal(xdr.AssetTypeAssetTypeNative)) + Expect(subject.PP.DestAsset.AlphaNum4).To(BeNil()) + Expect(subject.PP.DestAsset.AlphaNum12).To(BeNil()) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + + Context("AlphaNum4", func() { + BeforeEach(func() { + mut = CreditAmount{"USD", address, "50"} + }) + It("sets the asset properly", func() { + Expect(subject.PP.DestAmount).To(Equal(xdr.Int64(500000000))) + Expect(subject.PP.DestAsset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4)) + Expect(subject.PP.DestAsset.AlphaNum4.AssetCode).To(Equal(xdr.AssetCode4{'U', 'S', 'D', 0})) + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.PP.DestAsset.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + Expect(subject.PP.DestAsset.AlphaNum12).To(BeNil()) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + + Context("AlphaNum12", func() { + BeforeEach(func() { + mut = CreditAmount{"ABCDEF", address, "50"} + }) + It("sets the asset properly", func() { + Expect(subject.PP.DestAmount).To(Equal(xdr.Int64(500000000))) + Expect(subject.PP.DestAsset.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum12)) + Expect(subject.PP.DestAsset.AlphaNum4).To(BeNil()) + Expect(subject.PP.DestAsset.AlphaNum12.AssetCode).To(Equal(xdr.AssetCode12{'A', 'B', 'C', 'D', 'E', 'F', 0, 0, 0, 0, 0, 0})) + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.PP.DestAsset.AlphaNum12.Issuer.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + }) + + Context("issuer invalid", func() { + BeforeEach(func() { + mut = CreditAmount{"ABCDEF", bad, "50"} + }) + + It("failed", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("amount invalid", func() { + BeforeEach(func() { + mut = CreditAmount{"ABCDEF", address, "test"} + }) + + It("failed", func() { + Expect(subject.Err).To(HaveOccurred()) + }) + }) + + Context("asset code length invalid", func() { + Context("empty", func() { + BeforeEach(func() { + mut = CreditAmount{"", address, "50.0"} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + + Context("too long", func() { + BeforeEach(func() { + mut = CreditAmount{"1234567890123", address, "50.0"} + }) + + It("failed", func() { + Expect(subject.Err.Error()).To(ContainSubstring("Asset code length is invalid")) + }) + }) + }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/set_options.go b/stellargohorizonclientv300/build/set_options.go new file mode 100644 index 000000000..79a2ee63e --- /dev/null +++ b/stellargohorizonclientv300/build/set_options.go @@ -0,0 +1,255 @@ +package build + +import ( + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// SetOptions groups the creation of a new SetOptions with a call to Mutate. +func SetOptions(muts ...interface{}) (result SetOptionsBuilder) { + result.Mutate(muts...) + return +} + +// SetOptionsMutator is a interface that wraps the +// MutateSetOptions operation. types may implement this interface to +// specify how they modify an xdr.SetOptionsOp object +type SetOptionsMutator interface { + MutateSetOptions(*xdr.SetOptionsOp) error +} + +// SetOptionsBuilder represents a transaction that is being built. +// Deprecated use txnbuild.SetOptions instead +type SetOptionsBuilder struct { + O xdr.Operation + SO xdr.SetOptionsOp + Err error +} + +// Mutate applies the provided mutators to this builder's payment or operation. +func (b *SetOptionsBuilder) Mutate(muts ...interface{}) { + for _, m := range muts { + var err error + switch mut := m.(type) { + case SetOptionsMutator: + err = mut.MutateSetOptions(&b.SO) + case OperationMutator: + err = mut.MutateOperation(&b.O) + default: + err = errors.New("Mutator type not allowed") + } + + if err != nil { + b.Err = errors.Wrap(err, "SetOptionsBuilder error") + return + } + } +} + +// MutateSetOptions for HomeDomain sets the SetOptionsOp's HomeDomain field +func (m HomeDomain) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + if len(m) > 32 { + return errors.New("HomeDomain is too long") + } + + value := xdr.String32(m) + o.HomeDomain = &value + return +} + +// MutateTransaction for HomeDomain allows creating an operation using a single mutator +func (m HomeDomain) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// MutateSetOptions for InflationDest sets the SetOptionsOp's InflationDest field +func (m InflationDest) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + o.InflationDest = &xdr.AccountId{} + err = setAccountId(string(m), o.InflationDest) + return +} + +// MutateTransaction for InflationDest allows creating an operation using a single mutator +func (m InflationDest) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// MutateSetOptions for MasterWeight sets the SetOptionsOp's MasterWeight field +func (m MasterWeight) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + val := xdr.Uint32(m) + o.MasterWeight = &val + return +} + +// MutateTransaction for MasterWeight allows creating an operation using a single mutator +func (m MasterWeight) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// AddSigner creates Signer mutator that sets account's signer +func AddSigner(address string, weight uint32) Signer { + return Signer{address, weight} +} + +// RemoveSigner creates Signer mutator that removes account's signer +func RemoveSigner(address string) Signer { + return Signer{address, 0} +} + +// MutateSetOptions for Signer sets the SetOptionsOp's signer field +func (m Signer) MutateSetOptions(o *xdr.SetOptionsOp) error { + + var signer xdr.Signer + signer.Weight = xdr.Uint32(m.Weight) + err := signer.Key.SetAddress(m.Address) + if err != nil { + return errors.Wrap(err, "failed to set address") + } + + o.Signer = &signer + return nil +} + +// MutateTransaction for Signer allows creating an operation using a single mutator +func (m Signer) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// SetThresholds creates Thresholds mutator +func SetThresholds(low, medium, high uint32) Thresholds { + return Thresholds{ + Low: &low, + Medium: &medium, + High: &high, + } +} + +// SetLowThreshold creates Thresholds mutator that sets account's low threshold +func SetLowThreshold(value uint32) Thresholds { + return Thresholds{Low: &value} +} + +// SetMediumThreshold creates Thresholds mutator that sets account's medium threshold +func SetMediumThreshold(value uint32) Thresholds { + return Thresholds{Medium: &value} +} + +// SetHighThreshold creates Thresholds mutator that sets account's high threshold +func SetHighThreshold(value uint32) Thresholds { + return Thresholds{High: &value} +} + +// MutateSetOptions for Thresholds sets the SetOptionsOp's thresholds fields +func (m Thresholds) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + if m.Low != nil { + val := xdr.Uint32(*m.Low) + o.LowThreshold = &val + } + + if m.Medium != nil { + val := xdr.Uint32(*m.Medium) + o.MedThreshold = &val + } + + if m.High != nil { + val := xdr.Uint32(*m.High) + o.HighThreshold = &val + } + + return +} + +// MutateTransaction for Thresholds allows creating an operation using a single mutator +func (m Thresholds) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// SetAuthRequired sets AuthRequiredFlag on SetOptions operation +func SetAuthRequired() SetFlag { + return SetFlag(xdr.AccountFlagsAuthRequiredFlag) +} + +// SetAuthRevocable sets AuthRevocableFlag on SetOptions operation +func SetAuthRevocable() SetFlag { + return SetFlag(xdr.AccountFlagsAuthRevocableFlag) +} + +// SetAuthImmutable sets AuthImmutableFlag on SetOptions operation +func SetAuthImmutable() SetFlag { + return SetFlag(xdr.AccountFlagsAuthImmutableFlag) +} + +// MutateSetOptions for SetFlag sets the SetOptionsOp's SetFlags field +func (m SetFlag) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + if !isFlagValid(xdr.AccountFlags(m)) { + return errors.New("Unknown flag in SetFlag mutator") + } + + var val xdr.Uint32 + if o.SetFlags == nil { + val = xdr.Uint32(m) + } else { + val = xdr.Uint32(m) | *o.SetFlags + } + o.SetFlags = &val + return +} + +// MutateTransaction for SetFlag allows creating an operation using a single mutator +func (m SetFlag) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +// ClearAuthRequired clears AuthRequiredFlag on SetOptions operation +func ClearAuthRequired() ClearFlag { + return ClearFlag(xdr.AccountFlagsAuthRequiredFlag) +} + +// ClearAuthRevocable clears AuthRevocableFlag on SetOptions operation +func ClearAuthRevocable() ClearFlag { + return ClearFlag(xdr.AccountFlagsAuthRevocableFlag) +} + +// ClearAuthImmutable clears AuthImmutableFlag on SetOptions operation +func ClearAuthImmutable() ClearFlag { + return ClearFlag(xdr.AccountFlagsAuthImmutableFlag) +} + +// MutateSetOptions for ClearFlag sets the SetOptionsOp's ClearFlags field +func (m ClearFlag) MutateSetOptions(o *xdr.SetOptionsOp) (err error) { + if !isFlagValid(xdr.AccountFlags(m)) { + return errors.New("Unknown flag in SetFlag mutator") + } + + var val xdr.Uint32 + if o.ClearFlags == nil { + val = xdr.Uint32(m) + } else { + val = xdr.Uint32(m) | *o.ClearFlags + } + o.ClearFlags = &val + return +} + +// MutateTransaction for ClearFlag allows creating an operation using a single mutator +func (m ClearFlag) MutateTransaction(t *TransactionBuilder) error { + return mutateTransactionBuilder(t, m) +} + +func isFlagValid(flag xdr.AccountFlags) bool { + if flag != xdr.AccountFlagsAuthRequiredFlag && + flag != xdr.AccountFlagsAuthRevocableFlag && + flag != xdr.AccountFlagsAuthImmutableFlag { + return false + } + return true +} + +func mutateTransactionBuilder(t *TransactionBuilder, m SetOptionsMutator) error { + builder := SetOptions(m) + if builder.Err != nil { + return builder.Err + } + t.Mutate(builder) + return nil +} diff --git a/stellargohorizonclientv300/build/set_options_test.go b/stellargohorizonclientv300/build/set_options_test.go new file mode 100644 index 000000000..17e705c24 --- /dev/null +++ b/stellargohorizonclientv300/build/set_options_test.go @@ -0,0 +1,209 @@ +package build + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" + "github.com/stretchr/testify/assert" +) + +func TestSetOptions_Signer(t *testing.T) { + cases := []struct { + Name string + Address string + Weight uint32 + Error string + }{ + { + Name: "AccountID", + Address: "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ", + Weight: 1, + }, + { + Name: "hash(x)", + Address: "XBU2RRGLXH3E5CQHTD3ODLDF2BWDCYUSSBLLZ5GNW7JXHDIYKXZWGTOG", + Weight: 2, + }, + { + Name: "hash(tx)", + Address: "TBU2RRGLXH3E5CQHTD3ODLDF2BWDCYUSSBLLZ5GNW7JXHDIYKXZWHXL7", + Weight: 3, + }, + { + Name: "Bad", + Address: "foo", + Weight: 1, + Error: "minimum valid length is 5", + }, + } + + for _, kase := range cases { + var m SetOptionsBuilder + m.Mutate(Signer{ + Address: kase.Address, + Weight: kase.Weight, + }) + + if kase.Error == "" { + if assert.NoError(t, m.Err, "Unexpected error on case %s", kase.Name) { + assert.Equal(t, kase.Address, m.SO.Signer.Key.Address()) + assert.Equal(t, kase.Weight, uint32(m.SO.Signer.Weight)) + } + } else { + assert.Contains(t, m.Err.Error(), kase.Error, + "Expected an error on case %s", kase.Name) + } + } +} + +var _ = Describe("SetOptionsBuilder Mutators", func() { + + var ( + subject SetOptionsBuilder + mut interface{} + + address = "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + bad = "foo" + ) + + JustBeforeEach(func() { + subject = SetOptionsBuilder{} + subject.Mutate(mut) + }) + + Describe("InflationDest", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = InflationDest(address) }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.SO.InflationDest.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = InflationDest(bad) }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("HomeDomain", func() { + Context("using a valid value", func() { + BeforeEach(func() { mut = HomeDomain("stellar.org") }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the HomeDomain to correct value", func() { + Expect(*subject.SO.HomeDomain).To(Equal(xdr.String32("stellar.org"))) + }) + }) + + Context("value too long", func() { + BeforeEach(func() { mut = HomeDomain("123456789012345678901234567890123") }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("SetFlag", func() { + Context("using a valid account flag", func() { + BeforeEach(func() { mut = SetFlag(1) }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the flag to the correct value", func() { + Expect(*subject.SO.SetFlags).To(Equal(xdr.Uint32(1))) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SetFlag(3) }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("ClearFlag", func() { + Context("using a valid account flag", func() { + BeforeEach(func() { mut = ClearFlag(1) }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the flag to the correct value", func() { + Expect(*subject.SO.ClearFlags).To(Equal(xdr.Uint32(1))) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = ClearFlag(3) }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) + + Describe("MasterWeight", func() { + Context("using a valid weight", func() { + BeforeEach(func() { mut = MasterWeight(1) }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the weight to the correct value", func() { + Expect(*subject.SO.MasterWeight).To(Equal(xdr.Uint32(1))) + }) + }) + }) + + Describe("Thresholds", func() { + Context("using a valid weight", func() { + BeforeEach(func() { + low := uint32(1) + med := uint32(2) + high := uint32(3) + mut = Thresholds{&low, &med, &high} + }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the thresholds to the correct value", func() { + Expect(*subject.SO.LowThreshold).To(Equal(xdr.Uint32(1))) + Expect(*subject.SO.MedThreshold).To(Equal(xdr.Uint32(2))) + Expect(*subject.SO.HighThreshold).To(Equal(xdr.Uint32(3))) + }) + }) + }) + + Describe("SourceAccount", func() { + Context("using a valid stellar address", func() { + BeforeEach(func() { mut = SourceAccount{address} }) + + It("succeeds", func() { + Expect(subject.Err).NotTo(HaveOccurred()) + }) + + It("sets the destination to the correct xdr.AccountId", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.O.SourceAccount.MustEd25519()).To(Equal(aid.MustEd25519())) + }) + }) + + Context("using an invalid value", func() { + BeforeEach(func() { mut = SourceAccount{bad} }) + It("failed", func() { Expect(subject.Err).To(HaveOccurred()) }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/testing.go b/stellargohorizonclientv300/build/testing.go new file mode 100644 index 000000000..7edfdd2b9 --- /dev/null +++ b/stellargohorizonclientv300/build/testing.go @@ -0,0 +1,28 @@ +package build + +import ( + "fmt" + + "github.com/stellar/go/xdr" +) + +// MockSequenceProvider is a mock sequence provider. +type MockSequenceProvider struct { + Data map[string]xdr.SequenceNumber +} + +var _ SequenceProvider = &MockSequenceProvider{} + +// SequenceForAccount implements `SequenceProvider` +func (sp *MockSequenceProvider) SequenceForAccount( + accountID string, +) (xdr.SequenceNumber, error) { + + ret, ok := sp.Data[accountID] + + if !ok { + return 0, fmt.Errorf("No sequence for %s in mock", accountID) + } + + return ret, nil +} diff --git a/stellargohorizonclientv300/build/transaction.go b/stellargohorizonclientv300/build/transaction.go new file mode 100644 index 000000000..7d75229aa --- /dev/null +++ b/stellargohorizonclientv300/build/transaction.go @@ -0,0 +1,358 @@ +package build + +import ( + "encoding/hex" + "fmt" + + "github.com/stellar/go/network" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// Transaction groups the creation of a new TransactionBuilder with a call +// to Mutate. +func Transaction(muts ...TransactionMutator) (*TransactionBuilder, error) { + result := &TransactionBuilder{} + err := result.Mutate(muts...) + if err != nil { + return nil, err + } + err = result.Mutate(Defaults{}) + if err != nil { + return nil, err + } + return result, nil +} + +// TransactionMutator is a interface that wraps the +// MutateTransaction operation. types may implement this interface to +// specify how they modify an xdr.Transaction object +type TransactionMutator interface { + MutateTransaction(*TransactionBuilder) error +} + +// TransactionBuilder represents a Transaction that is being constructed. +// Deprecated use txnbuild.Transaction instead +type TransactionBuilder struct { + TX *xdr.TransactionV0 + NetworkPassphrase string + BaseFee uint64 +} + +// Mutate applies the provided TransactionMutators to this builder's transaction +func (b *TransactionBuilder) Mutate(muts ...TransactionMutator) error { + if b.TX == nil { + b.TX = &xdr.TransactionV0{} + } + + for i, m := range muts { + err := m.MutateTransaction(b) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("mutator:%d failed", i)) + } + } + + return nil +} + +// Hash returns the hash of this builder's transaction. +func (b *TransactionBuilder) Hash() ([32]byte, error) { + return network.HashTransactionV0(*b.TX, b.NetworkPassphrase) +} + +// HashHex returns the hex-encoded hash of this builder's transaction +func (b *TransactionBuilder) HashHex() (string, error) { + hash, err := b.Hash() + if err != nil { + return "", err + } + + return hex.EncodeToString(hash[:]), nil +} + +// Sign returns an new TransactionEnvelopeBuilder using this builder's +// transaction as the basis and with signatures of that transaction from the +// provided Signers. +func (b *TransactionBuilder) Sign(signers ...string) (TransactionEnvelopeBuilder, error) { + var result TransactionEnvelopeBuilder + err := result.Mutate(b) + if err != nil { + return result, err + } + + for _, s := range signers { + err := result.Mutate(Sign{s}) + if err != nil { + return result, err + } + } + + return result, nil +} + +// Envelope returns a new TransactionEnvelopeBuilder using this +// builder's transaction as the basis and with the provided +// mutators applied. +func (b *TransactionBuilder) Envelope(muts ...TransactionEnvelopeMutator) (TransactionEnvelopeBuilder, error) { + var teb TransactionEnvelopeBuilder + err := teb.Mutate(b) + if err != nil { + return teb, err + } + err = teb.Mutate(muts...) + return teb, err +} + +// ------------------------------------------------------------ +// +// Mutator implementations +// +// ------------------------------------------------------------ + +// MutateTransaction for AccountMergeBuilder causes the underylying Destination +// to be added to the operation list for the provided transaction +func (m AccountMergeBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeAccountMerge, m.Destination) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for AllowTrustBuilder causes the underylying AllowTrustOp +// to be added to the operation list for the provided transaction +func (m AllowTrustBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeAllowTrust, m.AT) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for AutoSequence loads the sequence and sets it on the tx. +// NOTE: this mutator assumes that the source account has already been set on +// the transaction and will error if that has not occurred. +func (m AutoSequence) MutateTransaction(o *TransactionBuilder) error { + source := xdr.AccountId{ + Type: xdr.PublicKeyTypePublicKeyTypeEd25519, + Ed25519: &o.TX.SourceAccountEd25519, + } + + if source == (xdr.AccountId{}) { + return errors.New("auto sequence used prior to setting source account") + } + + seq, err := m.SequenceForAccount(source.Address()) + if err != nil { + return errors.Wrap(err, "couldn't load account for auto sequence") + } + + o.TX.SeqNum = seq + 1 + return nil +} + +// MutateTransaction for BumpSequenceBuilder causes the underylying BumpSequenceOp +// to be added to the operation list for the provided transaction +func (m BumpSequenceBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeBumpSequence, m.BS) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for ChangeTrustBuilder causes the underylying +// CreateAccountOp to be added to the operation list for the provided +// transaction +func (m ChangeTrustBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeChangeTrust, m.CT) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for CreateAccountBuilder causes the underylying +// CreateAccountOp to be added to the operation list for the provided +// transaction +func (m CreateAccountBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreateAccount, m.CA) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// DefaultBaseFee is used to calculate the transaction fee by default +var DefaultBaseFee uint64 = 100 + +// MutateTransaction for Defaults sets reasonable defaults on the transaction being built +func (m Defaults) MutateTransaction(o *TransactionBuilder) error { + + if o.BaseFee == 0 { + o.BaseFee = DefaultBaseFee + } + if o.TX.Fee == 0 { + o.TX.Fee = xdr.Uint32(int(o.BaseFee) * len(o.TX.Operations)) + } + + if o.NetworkPassphrase == "" { + o.NetworkPassphrase = DefaultNetwork.Passphrase + } + return nil +} + +// MutateTransaction for InflationBuilder causes the underylying +// InflationOp to be added to the operation list for the provided +// transaction +func (m InflationBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeInflation, nil) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for ManageDataBuilder causes the underylying +// ManageData to be added to the operation list for the provided +// transaction +func (m ManageDataBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeManageData, m.MD) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for ManageOfferBuilder causes the underylying +// ManageData to be added to the operation list for the provided +// transaction +func (m ManageOfferBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + if m.PassiveOffer { + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeCreatePassiveSellOffer, m.PO) + o.TX.Operations = append(o.TX.Operations, m.O) + } else { + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeManageSellOffer, m.MO) + o.TX.Operations = append(o.TX.Operations, m.O) + } + return m.Err +} + +// MutateTransaction for MemoHash sets the memo. +func (m MemoHash) MutateTransaction(o *TransactionBuilder) (err error) { + o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoHash, m.Value) + return +} + +// MutateTransaction for MemoID sets the memo. +func (m MemoID) MutateTransaction(o *TransactionBuilder) (err error) { + o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoId, xdr.Uint64(m.Value)) + return +} + +// MutateTransaction for MemoReturn sets the memo. +func (m MemoReturn) MutateTransaction(o *TransactionBuilder) (err error) { + o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoReturn, m.Value) + return +} + +// MutateTransaction for MemoText sets the memo. +func (m MemoText) MutateTransaction(o *TransactionBuilder) (err error) { + + if len([]byte(m.Value)) > MemoTextMaxLength { + err = errors.New("Memo too long; over 28 bytes") + return + } + + o.TX.Memo, err = xdr.NewMemo(xdr.MemoTypeMemoText, m.Value) + return +} + +func (m Timebounds) MutateTransaction(o *TransactionBuilder) error { + o.TX.TimeBounds = &xdr.TimeBounds{MinTime: xdr.TimePoint(m.MinTime), MaxTime: xdr.TimePoint(m.MaxTime)} + return nil +} + +// MutateTransaction for Network sets the Network ID to use when signing this transaction +func (m Network) MutateTransaction(o *TransactionBuilder) error { + o.NetworkPassphrase = m.Passphrase + return nil +} + +// MutateTransaction for PaymentBuilder causes the underylying PaymentOp +// or PathPaymentOp to be added to the operation list for the provided transaction +func (m PaymentBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + if m.PathPayment { + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePathPaymentStrictReceive, m.PP) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypePayment, m.P) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for SetOptionsBuilder causes the underylying +// SetOptionsOp to be added to the operation list for the provided +// transaction +func (m SetOptionsBuilder) MutateTransaction(o *TransactionBuilder) error { + if m.Err != nil { + return m.Err + } + + m.O.Body, m.Err = xdr.NewOperationBody(xdr.OperationTypeSetOptions, m.SO) + o.TX.Operations = append(o.TX.Operations, m.O) + return m.Err +} + +// MutateTransaction for Sequence sets the SeqNum on the transaction. +func (m Sequence) MutateTransaction(o *TransactionBuilder) error { + o.TX.SeqNum = xdr.SequenceNumber(m.Sequence) + return nil +} + +// MutateTransaction for SourceAccount sets the transaction's SourceAccount +// to the pubilic key for the address provided +func (m SourceAccount) MutateTransaction(o *TransactionBuilder) error { + source := xdr.AccountId{} + err := setAccountId(m.AddressOrSeed, &source) + if err != nil { + return err + } + id, ok := source.GetEd25519() + if !ok { + return errors.New("invalid account id") + } + o.TX.SourceAccountEd25519 = id + return nil +} + +// MutateTransaction for BaseFee sets the base fee +func (m BaseFee) MutateTransaction(o *TransactionBuilder) error { + o.BaseFee = m.Amount + + return nil +} diff --git a/stellargohorizonclientv300/build/transaction_envelope.go b/stellargohorizonclientv300/build/transaction_envelope.go new file mode 100644 index 000000000..dc6bdda3b --- /dev/null +++ b/stellargohorizonclientv300/build/transaction_envelope.go @@ -0,0 +1,128 @@ +package build + +import ( + "bytes" + "encoding/base64" + "fmt" + + "github.com/stellar/go/keypair" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +// TransactionEnvelopeMutator is a interface that wraps the +// MutateTransactionEnvelope operation. types may implement this interface to +// specify how they modify an xdr.TransactionEnvelope object +type TransactionEnvelopeMutator interface { + MutateTransactionEnvelope(*TransactionEnvelopeBuilder) error +} + +// TransactionEnvelopeBuilder helps you build a TransactionEnvelope +type TransactionEnvelopeBuilder struct { + E *xdr.TransactionEnvelope + // TODO support fee bump transactions + + child *TransactionBuilder +} + +func (b *TransactionEnvelopeBuilder) Init() { + if b.E == nil { + b.E = &xdr.TransactionEnvelope{ + Type: xdr.EnvelopeTypeEnvelopeTypeTxV0, + V0: &xdr.TransactionV0Envelope{}, + } + } + + if b.child == nil { + // TODO support fee bump transactions + b.child = &TransactionBuilder{TX: &b.E.V0.Tx} + } +} + +// Mutate applies the provided TransactionEnvelopeMutators to this builder's +// envelope +func (b *TransactionEnvelopeBuilder) Mutate(muts ...TransactionEnvelopeMutator) error { + b.Init() + + for i, m := range muts { + err := m.MutateTransactionEnvelope(b) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("mutator:%d failed", i)) + } + } + + return nil +} + +// MutateTX runs Mutate on the underlying transaction using the provided +// mutators. +func (b *TransactionEnvelopeBuilder) MutateTX(muts ...TransactionMutator) error { + b.Init() + + err := b.child.Mutate(muts...) + if err != nil { + return err + } + + return nil +} + +// Bytes encodes the builder's underlying envelope to XDR +func (b *TransactionEnvelopeBuilder) Bytes() ([]byte, error) { + var txBytes bytes.Buffer + _, err := xdr.Marshal(&txBytes, b.E) + if err != nil { + return nil, errors.Wrap(err, "marshal xdr failed") + } + + return txBytes.Bytes(), nil +} + +// Base64 returns a string which is the xdr-then-base64-encoded form +// of the builder's underlying transaction envelope +func (b *TransactionEnvelopeBuilder) Base64() (string, error) { + bs, err := b.Bytes() + if err != nil { + return "", errors.Wrap(err, "get raw bytes failed") + } + + return base64.StdEncoding.EncodeToString(bs), nil +} + +// ------------------------------------------------------------ +// +// Mutator implementations +// +// ------------------------------------------------------------ + +// MutateTransactionEnvelope adds a signature to the provided envelope +func (m Sign) MutateTransactionEnvelope(txe *TransactionEnvelopeBuilder) error { + hash, err := txe.child.Hash() + if err != nil { + return errors.Wrap(err, "hash tx failed") + } + + kp, err := keypair.Parse(m.Seed) + if err != nil { + return errors.Wrap(err, "parse failed") + } + + sig, err := kp.SignDecorated(hash[:]) + if err != nil { + return errors.Wrap(err, "sign tx failed") + } + + txe.E.V0.Signatures = append(txe.E.V0.Signatures, sig) + return nil +} + +// MutateTransactionEnvelope for TransactionBuilder causes the underylying +// transaction to be set as the provided envelope's Tx field +func (m *TransactionBuilder) MutateTransactionEnvelope(txe *TransactionEnvelopeBuilder) error { + // TODO support fee bump transactions + txe.E.V0.Tx = *m.TX + newChild := *m + txe.child = &newChild + m.TX = &txe.E.V0.Tx + return nil +} diff --git a/stellargohorizonclientv300/build/transaction_envelope_test.go b/stellargohorizonclientv300/build/transaction_envelope_test.go new file mode 100644 index 000000000..aa231d1d4 --- /dev/null +++ b/stellargohorizonclientv300/build/transaction_envelope_test.go @@ -0,0 +1,53 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("TransactionEnvelope Mutators:", func() { + + var ( + subject TransactionEnvelopeBuilder + mut TransactionEnvelopeMutator + err error + ) + + BeforeEach(func() { subject = TransactionEnvelopeBuilder{} }) + JustBeforeEach(func() { err = subject.Mutate(mut) }) + + Describe("TransactionBuilder", func() { + Context("that is valid", func() { + BeforeEach(func() { + var err2 error + mut, err2 = Transaction(Sequence{10}) + Expect(err2).NotTo(HaveOccurred()) + }) + It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) }) + It("sets the TX", func() { Expect(subject.E.V0.Tx.SeqNum).To(BeEquivalentTo(10)) }) + }) + }) + + Describe("Sign", func() { + Context("with a valid key", func() { + BeforeEach(func() { + subject.MutateTX(SourceAccount{"SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H"}, TestNetwork) + mut = Sign{"SDOTALIMPAM2IV65IOZA7KZL7XWZI5BODFXTRVLIHLQZQCKK57PH5F3H"} + }) + + It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) }) + It("adds a signature to the envelope", func() { + Expect(subject.E.V0.Signatures).To(HaveLen(1)) + }) + }) + + Context("with an invalid key", func() { + BeforeEach(func() { mut = Sign{""} }) + + It("fails", func() { + Expect(err).To(HaveOccurred()) + }) + }) + }) + +}) diff --git a/stellargohorizonclientv300/build/transaction_test.go b/stellargohorizonclientv300/build/transaction_test.go new file mode 100644 index 000000000..f66e364bd --- /dev/null +++ b/stellargohorizonclientv300/build/transaction_test.go @@ -0,0 +1,186 @@ +package build + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/stellar/go/xdr" +) + +var _ = Describe("Transaction Mutators:", func() { + + var ( + subject *TransactionBuilder + mut TransactionMutator + err error + ) + + BeforeEach(func() { subject = &TransactionBuilder{} }) + JustBeforeEach(func() { err = subject.Mutate(mut) }) + + Describe("Defaults", func() { + BeforeEach(func() { + subject.Mutate(Payment()) + mut = Defaults{} + }) + It("sets the fee", func() { Expect(subject.TX.Fee).To(BeEquivalentTo(DefaultBaseFee)) }) + It("sets the network passphrase", func() { Expect(subject.NetworkPassphrase).To(Equal(DefaultNetwork.Passphrase)) }) + + Context("on a transaction with 2 operations", func() { + BeforeEach(func() { subject.Mutate(Payment()) }) + It("sets the fee to 200", func() { Expect(subject.TX.Fee).To(BeEquivalentTo(200)) }) + }) + }) + + Describe("TransactionBuilder.BaseFee", func() { + BeforeEach(func() { + subject.Mutate(Payment()) + mut = Defaults{} + }) + It("sets the fee", func() { Expect(subject.TX.Fee).To(BeEquivalentTo(DefaultBaseFee)) }) + + Context("trying to change the base fee to 333", func() { + BeforeEach(func() { + subject.BaseFee = 333 + subject.Mutate(Payment()) + }) + It( + "sets the fee to 333 * 2", + func() { Expect(subject.TX.Fee).To(BeEquivalentTo(333 * 2)) }, + ) + }) + }) + + Describe("BaseFee Mutator", func() { + BeforeEach(func() { + subject.Mutate(BaseFee{Amount: 456}, Defaults{}) + }) + It( + "sets the base fee to 456", + func() { Expect(subject.BaseFee).To(BeEquivalentTo(456)) }, + ) + + Context("on a transaction with 3 operations", func() { + BeforeEach(func() { + subject.Mutate(Payment()) + subject.Mutate(Payment()) + subject.Mutate(Payment()) + }) + It( + "sets the fee to 456 * 3", + func() { Expect(subject.TX.Fee).To(BeEquivalentTo(456 * 3)) }, + ) + }) + }) + + Describe("MemoHash", func() { + BeforeEach(func() { mut = MemoHash{[32]byte{0x01}} }) + It("sets a Hash memo on the transaction", func() { + Expect(subject.TX.Memo.Type).To(Equal(xdr.MemoTypeMemoHash)) + Expect(subject.TX.Memo.MustHash()).To(Equal(xdr.Hash([32]byte{0x01}))) + }) + }) + + Describe("MemoID", func() { + BeforeEach(func() { mut = MemoID{123} }) + It("sets an ID memo on the transaction", func() { + Expect(subject.TX.Memo.Type).To(Equal(xdr.MemoTypeMemoId)) + Expect(subject.TX.Memo.MustId()).To(Equal(xdr.Uint64(123))) + }) + }) + + Describe("MemoReturn", func() { + BeforeEach(func() { mut = MemoReturn{[32]byte{0x01}} }) + It("sets a Hash memo on the transaction", func() { + Expect(subject.TX.Memo.Type).To(Equal(xdr.MemoTypeMemoReturn)) + Expect(subject.TX.Memo.MustRetHash()).To(Equal(xdr.Hash([32]byte{0x01}))) + }) + }) + + Describe("MemoText", func() { + BeforeEach(func() { mut = MemoText{"hello"} }) + It("sets a TEXT memo on the transaction", func() { + Expect(subject.TX.Memo.Type).To(Equal(xdr.MemoTypeMemoText)) + Expect(subject.TX.Memo.MustText()).To(Equal("hello")) + }) + + Context("a string longer than 28 bytes", func() { + BeforeEach(func() { mut = MemoText{"12345678901234567890123456789"} }) + It("sets an error", func() { + Expect(err).ToNot(BeNil()) + }) + }) + }) + + Describe("Timebounds", func() { + BeforeEach(func() { mut = Timebounds{1521056118, 1521056298} }) + It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) }) + It("sets an minimum and maximum timebound on the transaction", func() { + Expect(subject.TX.TimeBounds.MinTime).To(Equal(xdr.TimePoint(1521056118))) + Expect(subject.TX.TimeBounds.MaxTime).To(Equal(xdr.TimePoint(1521056298))) + }) + }) + + Describe("AllowTrustBuilder", func() { + BeforeEach(func() { mut = AllowTrust() }) + It("adds itself to the tx's operations", func() { + Expect(subject.TX.Operations).To(HaveLen(1)) + }) + }) + + Describe("PaymentBuilder", func() { + BeforeEach(func() { mut = Payment() }) + It("adds itself to the tx's operations", func() { + Expect(subject.TX.Operations).To(HaveLen(1)) + }) + }) + + Describe("SourceAccount", func() { + Context("with a valid address", func() { + address := "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ" + BeforeEach(func() { mut = SourceAccount{address} }) + It("sets the AccountId correctly", func() { + var aid xdr.AccountId + aid.SetAddress(address) + Expect(subject.TX.SourceAccountEd25519).To(Equal(aid.MustEd25519())) + }) + }) + + Context("with bad address", func() { + BeforeEach(func() { mut = SourceAccount{"foo"} }) + It("fails", func() { Expect(err).To(HaveOccurred()) }) + }) + }) + + Describe("Sequence", func() { + BeforeEach(func() { mut = Sequence{12345} }) + It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) }) + It("sets the sequence", func() { Expect(subject.TX.SeqNum).To(BeEquivalentTo(12345)) }) + }) + + Describe("AutoSequence", func() { + BeforeEach(func() { + mock := &MockSequenceProvider{ + Data: map[string]xdr.SequenceNumber{ + "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ": 2, + }, + } + + mut = AutoSequence{mock} + }) + + Context("with no source account set", func() { + It("fails", func() { Expect(err).To(HaveOccurred()) }) + }) + + Context("with a source account set", func() { + BeforeEach(func() { + subject.Mutate(SourceAccount{ + "GAXEMCEXBERNSRXOEKD4JAIKVECIXQCENHEBRVSPX2TTYZPMNEDSQCNQ", + }) + }) + + It("succeeds", func() { Expect(err).NotTo(HaveOccurred()) }) + It("sets the sequence", func() { Expect(subject.TX.SeqNum).To(BeEquivalentTo(3)) }) + }) + }) +}) diff --git a/stellargohorizonclientv300/build/util.go b/stellargohorizonclientv300/build/util.go new file mode 100644 index 000000000..c22798a03 --- /dev/null +++ b/stellargohorizonclientv300/build/util.go @@ -0,0 +1,59 @@ +package build + +import ( + "github.com/stellar/go/keypair" + "github.com/stellar/go/support/errors" + "github.com/stellar/go/xdr" +) + +func setAccountId(addressOrSeed string, aid *xdr.AccountId) error { + kp, err := keypair.Parse(addressOrSeed) + if err != nil { + return err + } + + if aid == nil { + return errors.New("aid is nil in setAccountId") + } + + return aid.SetAddress(kp.Address()) +} + +func setMuxedAccount(addressOrSeed string, m *xdr.MuxedAccount) error { + kp, err := keypair.Parse(addressOrSeed) + if err != nil { + return err + } + + if m == nil { + return errors.New("m is nil in setMuxedAccount") + } + + return m.SetAddress(kp.Address()) +} + +func createAlphaNumAsset(code, issuerAccountId string) (xdr.Asset, error) { + var issuer xdr.AccountId + err := setAccountId(issuerAccountId, &issuer) + if err != nil { + return xdr.Asset{}, err + } + + length := len(code) + switch { + case length >= 1 && length <= 4: + var codeArray xdr.AssetCode4 + byteArray := []byte(code) + copy(codeArray[:], byteArray[0:length]) + asset := xdr.AlphaNum4{AssetCode: codeArray, Issuer: issuer} + return xdr.NewAsset(xdr.AssetTypeAssetTypeCreditAlphanum4, asset) + case length >= 5 && length <= 12: + var codeArray xdr.AssetCode12 + byteArray := []byte(code) + copy(codeArray[:], byteArray[0:length]) + asset := xdr.AlphaNum12{AssetCode: codeArray, Issuer: issuer} + return xdr.NewAsset(xdr.AssetTypeAssetTypeCreditAlphanum12, asset) + default: + return xdr.Asset{}, errors.New("Asset code length is invalid") + } +} diff --git a/support/postgresdb/postgresdb.go b/support/postgresdb/postgresdb.go new file mode 100644 index 000000000..df3163208 --- /dev/null +++ b/support/postgresdb/postgresdb.go @@ -0,0 +1,3 @@ +package postgresdb + +import _ "github.com/lib/pq" diff --git a/terminator/terminator.go b/terminator/terminator.go index 67b1a631c..1e7b6906a 100644 --- a/terminator/terminator.go +++ b/terminator/terminator.go @@ -101,7 +101,7 @@ func (t *Terminator) run() { &txnbuild.ManageData{ Name: terminatorKey, Value: []byte(tsMillisStr), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }, } @@ -146,22 +146,22 @@ func (t *Terminator) deleteOffers(sellOffers []hProtocol.Offer, buyOffers []hPro // delete existing data entries ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(0), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(1), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) if len(botKey.AssetBaseIssuer) > 0 { ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(2), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) } ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(3), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) if len(botKey.AssetQuoteIssuer) > 0 { ops = append(ops, &txnbuild.ManageData{Name: botKey.FullKey(4), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) } @@ -170,7 +170,7 @@ func (t *Terminator) deleteOffers(sellOffers []hProtocol.Offer, buyOffers []hPro ops = append(ops, &txnbuild.ManageData{ Name: terminatorKey, Value: []byte(tsMillisStr), - SourceAccount: &txnbuild.SimpleAccount{AccountID: t.tradingAccount}, + SourceAccount: t.tradingAccount, }) log.Printf("deleting %d offers and 5 data entries, updating delete timestamp to %s\n", numOffers, tsMillisStr) diff --git a/trader/trader.go b/trader/trader.go index e9f55c46b..9092e1f35 100644 --- a/trader/trader.go +++ b/trader/trader.go @@ -10,7 +10,7 @@ import ( "github.com/nikhilsaraf/go-tools/multithreading" - "github.com/stellar/go/build" + "github.com/stellar/kelp/stellargohorizonclientv300/build" "github.com/stellar/go/clients/horizonclient" hProtocol "github.com/stellar/go/protocols/horizon" "github.com/stellar/go/txnbuild"