Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clients/horizon: Extend client with Offer details support #2303

Merged
merged 4 commits into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions clients/horizonclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"io"
"net/http"
"net/url"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -345,6 +346,23 @@ func (c *Client) Offers(request OfferRequest) (offers hProtocol.OffersPage, err
return
}

// OfferDetails returns information for a single offer.
// See https://www.stellar.org/developers/horizon/reference/endpoints/offer-details.html
func (c *Client) OfferDetails(offerID string) (offer hProtocol.Offer, err error) {
if len(offerID) == 0 {
err = errors.New("no offer ID provided")
return
}

if _, err = strconv.ParseInt(offerID, 10, 64); err != nil {
err = errors.New("invalid offer ID provided")
return
}

err = c.sendRequest(OfferRequest{OfferID: offerID}, &offer)
return
}

// Operations returns stellar operations (https://www.stellar.org/developers/horizon/reference/resources/operation.html)
// It can be used to return operations for an account, a ledger, a transaction and all operations on the network.
func (c *Client) Operations(request OperationRequest) (ops operations.OperationsPage, err error) {
Expand Down
12 changes: 11 additions & 1 deletion clients/horizonclient/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ func ExampleClient_NextOffersPage() {
fmt.Println(nextPage)
}
}

func ExampleClient_NextOperationsPage() {
client := horizonclient.DefaultPublicNetClient
// all operations
Expand Down Expand Up @@ -410,6 +409,17 @@ func ExampleClient_NextTransactionsPage() {
}
}

func ExampleClient_OfferDetails() {
client := horizonclient.DefaultPublicNetClient
offer, err := client.OfferDetails("2")
if err != nil {
fmt.Println(err)
return
}

fmt.Print(offer)
}

func ExampleClient_Offers() {
client := horizonclient.DefaultPublicNetClient
offerRequest := horizonclient.OfferRequest{
Expand Down
3 changes: 2 additions & 1 deletion clients/horizonclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ type ClientInterface interface {
Metrics() (hProtocol.Metrics, error)
FeeStats() (hProtocol.FeeStats, error)
Offers(request OfferRequest) (hProtocol.OffersPage, error)
OfferDetails(offerID string) (offer hProtocol.Offer, err error)
Operations(request OperationRequest) (operations.OperationsPage, error)
OperationDetail(id string) (operations.Operation, error)
SubmitTransactionXDR(transactionXdr string) (hProtocol.TransactionSuccess, error)
Expand Down Expand Up @@ -275,9 +276,9 @@ type feeStatsRequest struct {
}

// OfferRequest struct contains data for getting offers made by an account from a horizon server.
// "ForAccount" is required.
// The query parameters (Order, Cursor and Limit) are optional. All or none can be set.
type OfferRequest struct {
OfferID string
ForAccount string
Selling string
Seller string
Expand Down
66 changes: 66 additions & 0 deletions clients/horizonclient/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,40 @@ func TestOfferRequest(t *testing.T) {
assert.Len(t, offers.Embedded.Records, 1)
}
}
func TestOfferDetailsRequest(t *testing.T) {
hmock := httptest.NewClient()
client := &Client{
HorizonURL: "https://localhost/",
HTTP: hmock,
}

// account offers
hmock.On(
"GET",
"https://localhost/offers/5635",
).ReturnString(200, offerResponse)

record, err := client.OfferDetails("5635")
if assert.NoError(t, err) {
assert.IsType(t, record, hProtocol.Offer{})
assert.Equal(t, record.ID, int64(5635))
assert.Equal(t, record.Seller, "GD6UOZ3FGFI5L2X6F52YPJ6ICSW375BNBZIQC4PCLSEOO6SMX7CUS5MB")
assert.Equal(t, record.PT, "5635")
assert.Equal(t, record.Selling.Type, "native")
assert.Equal(t, record.Buying.Code, "AstroDollar")
assert.Equal(t, record.Buying.Issuer, "GDA2EHKPDEWZTAL6B66FO77HMOZL3RHZTIJO7KJJK5RQYSDUXEYMPJYY")
assert.Equal(t, record.Amount, "100.0000000")
assert.Equal(t, record.LastModifiedLedger, int32(356183))
}

_, err = client.OfferDetails("S6ES")
assert.Error(t, err)
assert.EqualError(t, err, "invalid offer ID provided")

_, err = client.OfferDetails("")
assert.Error(t, err)
assert.EqualError(t, err, "no offer ID provided")
}

func TestOperationsRequest(t *testing.T) {
hmock := httptest.NewClient()
Expand Down Expand Up @@ -1474,6 +1508,38 @@ var offersResponse = `{
}
}`

var offerResponse = `
{
"_links": {
"self": {
"href": "https://horizon-testnet.stellar.org/offers/5635"
},
"offer_maker": {
"href": "https://horizon-testnet.stellar.org/accounts/GD6UOZ3FGFI5L2X6F52YPJ6ICSW375BNBZIQC4PCLSEOO6SMX7CUS5MB"
}
},
"id": "5635",
"paging_token": "5635",
"seller": "GD6UOZ3FGFI5L2X6F52YPJ6ICSW375BNBZIQC4PCLSEOO6SMX7CUS5MB",
"selling": {
"asset_type": "native"
},
"buying": {
"asset_type": "credit_alphanum12",
"asset_code": "AstroDollar",
"asset_issuer": "GDA2EHKPDEWZTAL6B66FO77HMOZL3RHZTIJO7KJJK5RQYSDUXEYMPJYY"
},
"amount": "100.0000000",
"price_r": {
"n": 10,
"d": 1
},
"price": "10.0000000",
"last_modified_ledger": 356183,
"last_modified_time": "2020-02-20T20:44:55Z"
}
`

var multipleOpsResponse = `{
"_links": {
"self": {
Expand Down
6 changes: 6 additions & 0 deletions clients/horizonclient/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ func (m *MockClient) Offers(request OfferRequest) (hProtocol.OffersPage, error)
return a.Get(0).(hProtocol.OffersPage), a.Error(1)
}

// OfferDetail is a mocking method
func (m *MockClient) OfferDetails(offerID string) (hProtocol.Offer, error) {
a := m.Called(offerID)
return a.Get(0).(hProtocol.Offer), a.Error(1)
}

// Operations is a mocking method
func (m *MockClient) Operations(request OperationRequest) (operations.OperationsPage, error) {
a := m.Called(request)
Expand Down
46 changes: 25 additions & 21 deletions clients/horizonclient/offer_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,33 @@ import (

// BuildURL creates the endpoint to be queried based on the data in the OfferRequest struct.
func (or OfferRequest) BuildURL() (endpoint string, err error) {
// backwards compatibility support
if len(or.ForAccount) > 0 {
endpoint = fmt.Sprintf("accounts/%s/offers", or.ForAccount)
queryParams := addQueryParams(cursor(or.Cursor), limit(or.Limit), or.Order)
if queryParams != "" {
endpoint = fmt.Sprintf("%s?%s", endpoint, queryParams)
}
if len(or.OfferID) > 0 {
endpoint = fmt.Sprintf("offers/%s", or.OfferID)
} else {
query := url.Values{}
if len(or.Seller) > 0 {
query.Add("seller", or.Seller)
}
if len(or.Selling) > 0 {
query.Add("selling", or.Selling)
}
if len(or.Buying) > 0 {
query.Add("buying", or.Buying)
}
// backwards compatibility support
if len(or.ForAccount) > 0 {
endpoint = fmt.Sprintf("accounts/%s/offers", or.ForAccount)
queryParams := addQueryParams(cursor(or.Cursor), limit(or.Limit), or.Order)
if queryParams != "" {
endpoint = fmt.Sprintf("%s?%s", endpoint, queryParams)
}
} else {
query := url.Values{}
if len(or.Seller) > 0 {
query.Add("seller", or.Seller)
}
if len(or.Selling) > 0 {
query.Add("selling", or.Selling)
}
if len(or.Buying) > 0 {
query.Add("buying", or.Buying)
}

endpoint = fmt.Sprintf("offers?%s", query.Encode())
pageParams := addQueryParams(cursor(or.Cursor), limit(or.Limit), or.Order)
if pageParams != "" {
endpoint = fmt.Sprintf("%s&%s", endpoint, pageParams)
endpoint = fmt.Sprintf("offers?%s", query.Encode())
pageParams := addQueryParams(cursor(or.Cursor), limit(or.Limit), or.Order)
if pageParams != "" {
endpoint = fmt.Sprintf("%s&%s", endpoint, pageParams)
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions clients/horizonclient/offer_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ func TestOfferRequestBuildUrl(t *testing.T) {
// It should return valid offers endpoint and no errors
require.NoError(t, err)
assert.Equal(t, "accounts/GCLWGQPMKXQSPF776IU33AH4PZNOOWNAWGGKVTBQMIC5IMKUNP3E6NVU/offers?cursor=now&order=desc", endpoint)

er = OfferRequest{OfferID: "12345"}
endpoint, err = er.BuildURL()

require.NoError(t, err)
assert.Equal(t, "offers/12345", endpoint)
}

func TestNextOffersPage(t *testing.T) {
Expand Down