Skip to content

Commit

Permalink
Add OfferDetail support to horizonclient.
Browse files Browse the repository at this point in the history
  • Loading branch information
abuiles committed Feb 20, 2020
1 parent 1fe83eb commit 2b2b5dc
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 22 deletions.
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) OfferDetail(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
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)
OfferDetail(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 TestOfferDetailRequest(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.OfferDetail("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.OfferDetail("S6ES")
assert.Error(t, err)
assert.EqualError(t, err, "Invalid offer ID provided")

_, err = client.OfferDetail("")
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) OfferDetail(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

0 comments on commit 2b2b5dc

Please sign in to comment.