Skip to content
This repository was archived by the owner on Sep 12, 2019. It is now read-only.

Commit 8cd1003

Browse files
authored
Merge pull request #91 from stellar/account-merge
Send account_merge operations to callbacks.receive
2 parents 21e7a32 + c3f06b3 commit 8cd1003

File tree

6 files changed

+127
-2
lines changed

6 files changed

+127
-2
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package horizon
2+
3+
// EffectsPageResponse contains page of effects returned by Horizon
4+
type EffectsPageResponse struct {
5+
Embedded struct {
6+
Records []EffectResponse
7+
} `json:"_embedded"`
8+
}
9+
10+
// EffectResponse contains effect data returned by Horizon
11+
type EffectResponse struct {
12+
Type string `json:"type"`
13+
Amount string `json:"amount"`
14+
}

src/github.com/stellar/gateway/horizon/main.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414
"time"
1515

16+
"github.com/stellar/go/support/errors"
1617
"github.com/stellar/go/xdr"
1718
)
1819

@@ -23,6 +24,7 @@ type PaymentHandler func(PaymentResponse) error
2324
type HorizonInterface interface {
2425
LoadAccount(accountID string) (response AccountResponse, err error)
2526
LoadMemo(p *PaymentResponse) (err error)
27+
LoadAccountMergeAmount(p *PaymentResponse) error
2628
LoadOperation(operationID string) (response PaymentResponse, err error)
2729
StreamPayments(accountID string, cursor *string, onPaymentHandler PaymentHandler) (err error)
2830
SubmitTransaction(txeBase64 string) (response SubmitTransactionResponse, err error)
@@ -125,6 +127,33 @@ func (h *Horizon) LoadMemo(p *PaymentResponse) (err error) {
125127
return json.NewDecoder(res.Body).Decode(&p.Memo)
126128
}
127129

130+
// LoadAccountMergeAmount loads `account_merge` operation amount from it's effects
131+
func (h *Horizon) LoadAccountMergeAmount(p *PaymentResponse) error {
132+
if p.Type != "account_merge" {
133+
return errors.New("Not `account_merge` operation")
134+
}
135+
136+
res, err := http.Get(p.Links.Effects.Href)
137+
if err != nil {
138+
return errors.Wrap(err, "Error getting effects for operation")
139+
}
140+
defer res.Body.Close()
141+
var page EffectsPageResponse
142+
err = json.NewDecoder(res.Body).Decode(&page)
143+
if err != nil {
144+
return errors.Wrap(err, "Error decoding effects page")
145+
}
146+
147+
for _, effect := range page.Embedded.Records {
148+
if effect.Type == "account_credited" {
149+
p.Amount = effect.Amount
150+
return nil
151+
}
152+
}
153+
154+
return errors.New("Could not find `account_credited` effect in `account_merge` operation effects")
155+
}
156+
128157
// StreamPayments streams incoming payments
129158
func (h *Horizon) StreamPayments(accountID string, cursor *string, onPaymentHandler PaymentHandler) (err error) {
130159
url := h.ServerURL + "/accounts/" + accountID + "/payments"

src/github.com/stellar/gateway/horizon/payment_response.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ type PaymentResponse struct {
1010
Transaction struct {
1111
Href string `json:"href"`
1212
} `json:"transaction"`
13+
Effects struct {
14+
Href string `json:"href"`
15+
} `json:"effects"`
1316
} `json:"_links"`
1417

1518
// payment/path_payment fields
@@ -20,6 +23,10 @@ type PaymentResponse struct {
2023
AssetIssuer string `json:"asset_issuer"`
2124
Amount string `json:"amount"`
2225

26+
// account_merge
27+
Account string `json:"account"`
28+
Into string `json:"into"`
29+
2330
// transaction fields
2431
Memo struct {
2532
Type string `json:"memo_type"`

src/github.com/stellar/gateway/listener/payment_listener.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,15 @@ func (pl *PaymentListener) onPayment(payment horizon.PaymentResponse) (err error
213213
// shouldProcessPayment returns false and text status if payment should not be processed
214214
// (ex. asset is different than allowed assets).
215215
func (pl *PaymentListener) shouldProcessPayment(payment horizon.PaymentResponse) (bool, string) {
216-
if payment.Type != "payment" && payment.Type != "path_payment" {
216+
if payment.Type != "payment" && payment.Type != "path_payment" && payment.Type != "account_merge" {
217217
return false, "Not a payment operation"
218218
}
219219

220-
if payment.To != pl.config.Accounts.ReceivingAccountID {
220+
if payment.Type == "account_merge" {
221+
payment.AssetType = "native"
222+
}
223+
224+
if payment.To != pl.config.Accounts.ReceivingAccountID && payment.Into != pl.config.Accounts.ReceivingAccountID {
221225
return false, "Operation sent not received"
222226
}
223227

@@ -229,6 +233,17 @@ func (pl *PaymentListener) shouldProcessPayment(payment horizon.PaymentResponse)
229233
}
230234

231235
func (pl *PaymentListener) process(payment horizon.PaymentResponse) error {
236+
if payment.Type == "account_merge" {
237+
payment.AssetType = "native"
238+
payment.From = payment.Account
239+
payment.To = payment.Into
240+
241+
err := pl.horizon.LoadAccountMergeAmount(&payment)
242+
if err != nil {
243+
return errors.Wrap(err, "Unable to load account_merge amount")
244+
}
245+
}
246+
232247
err := pl.horizon.LoadMemo(&payment)
233248
if err != nil {
234249
return errors.Wrap(err, "Unable to load transaction memo")

src/github.com/stellar/gateway/listener/payment_listener_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,60 @@ func TestPaymentListener(t *testing.T) {
347347
})
348348
})
349349

350+
Convey("When receive callback returns success (account_merge)", func() {
351+
operation.Type = "account_merge"
352+
operation.Account = "GBL27BKG2JSDU6KQ5YJKCDWTVIU24VTG4PLB63SF4K2DBZS5XZMWRPVU"
353+
operation.Into = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB"
354+
operation.Amount = "100"
355+
operation.Memo.Type = "text"
356+
operation.Memo.Value = "testing"
357+
358+
// Updated in the listener
359+
operation.From = "GBL27BKG2JSDU6KQ5YJKCDWTVIU24VTG4PLB63SF4K2DBZS5XZMWRPVU"
360+
operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB"
361+
operation.AssetType = "native"
362+
363+
config.Assets[1].Code = "XLM"
364+
config.Assets[1].Issuer = ""
365+
366+
mockRepository.On("GetReceivedPaymentByOperationID", int64(1)).Return(nil, nil).Once()
367+
mockHorizon.On("LoadAccountMergeAmount", &operation).Return(nil).Once()
368+
mockHorizon.On("LoadMemo", &operation).Return(nil).Once()
369+
370+
mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")).
371+
Run(ensurePaymentStatus(t, operation, "Processing...")).Return(nil).Once()
372+
373+
mockEntityManager.On("Persist", mock.AnythingOfType("*entities.ReceivedPayment")).
374+
Run(ensurePaymentStatus(t, operation, "Success")).Return(nil).Once()
375+
376+
mockHTTPClient.On(
377+
"Do",
378+
mock.MatchedBy(func(req *http.Request) bool {
379+
return req.URL.String() == "http://receive_callback"
380+
}),
381+
).Return(
382+
net.BuildHTTPResponse(200, "ok"),
383+
nil,
384+
).Run(func(args mock.Arguments) {
385+
req := args.Get(0).(*http.Request)
386+
387+
assert.Equal(t, operation.Account, req.PostFormValue("from"))
388+
assert.Equal(t, operation.Amount, req.PostFormValue("amount"))
389+
assert.Equal(t, operation.AssetCode, req.PostFormValue("asset_code"))
390+
assert.Equal(t, operation.AssetIssuer, req.PostFormValue("asset_issuer"))
391+
assert.Equal(t, operation.Memo.Type, req.PostFormValue("memo_type"))
392+
assert.Equal(t, operation.Memo.Value, req.PostFormValue("memo"))
393+
}).Once()
394+
395+
Convey("it should save the status", func() {
396+
err := paymentListener.onPayment(operation)
397+
assert.Nil(t, err)
398+
mockHorizon.AssertExpectations(t)
399+
mockEntityManager.AssertExpectations(t)
400+
mockRepository.AssertExpectations(t)
401+
})
402+
})
403+
350404
Convey("When receive callback returns success (no memo)", func() {
351405
operation.Type = "payment"
352406
operation.To = "GATKP6ZQM5CSLECPMTAC5226PE367QALCPM6AFHTSULPPZMT62OOPMQB"

src/github.com/stellar/gateway/mocks/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func (m *MockHorizon) LoadMemo(p *horizon.PaymentResponse) (err error) {
102102
return a.Error(0)
103103
}
104104

105+
// LoadAccountMergeAmount is a mocking a method
106+
func (m *MockHorizon) LoadAccountMergeAmount(p *horizon.PaymentResponse) (err error) {
107+
a := m.Called(p)
108+
return a.Error(0)
109+
}
110+
105111
// StreamPayments is a mocking a method
106112
func (m *MockHorizon) StreamPayments(accountID string, cursor *string, onPaymentHandler horizon.PaymentHandler) (err error) {
107113
a := m.Called(accountID, cursor, onPaymentHandler)

0 commit comments

Comments
 (0)