Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
fix fill tracker to also work with path_payment type operations for s…
Browse files Browse the repository at this point in the history
…dex, fixes #219

* 1 - use effects to getOrderAction so it works with both types of operations: manage_offer and path_payment
  • Loading branch information
nikhilsaraf committed Aug 19, 2019
1 parent 4d2bb9b commit fb6f4d4
Showing 1 changed file with 115 additions and 40 deletions.
155 changes: 115 additions & 40 deletions plugins/sdex.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ func MakeSDEX(
threadTracker: threadTracker,
operationalBuffer: operationalBuffer,
operationalBufferNonNativePct: operationalBufferNonNativePct,
simMode: simMode,
pair: pair,
assetMap: assetMap,
opFeeStroopsFn: opFeeStroopsFn,
tradingOnSdex: exchangeShim == nil,
ocOverridesHandler: MakeEmptyOrderConstraintsOverridesHandler(),
simMode: simMode,
pair: pair,
assetMap: assetMap,
opFeeStroopsFn: opFeeStroopsFn,
tradingOnSdex: exchangeShim == nil,
ocOverridesHandler: MakeEmptyOrderConstraintsOverridesHandler(),
}

if exchangeShim == nil {
Expand Down Expand Up @@ -584,8 +584,17 @@ func (sdex *SDEX) GetTradeHistory(pair model.TradingPair, maybeCursorStart inter
}
}

func makeEffectsLink(trade hProtocol.Trade) string {
effectsLink := trade.Links.Operation.Href
if !strings.HasSuffix(effectsLink, "/") {
effectsLink = effectsLink + "/"
}
return effectsLink + "effects?limit=200"
}

func (sdex *SDEX) getOrderAction(baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset, trade hProtocol.Trade) (*model.OrderAction, error) {
if trade.BaseAccount != sdex.TradingAccount && trade.CounterAccount != sdex.TradingAccount {
// if the trade is different from what we expect for this bot instance then return empty values so we ignore this trade
return nil, nil
}

Expand All @@ -603,50 +612,116 @@ func (sdex *SDEX) getOrderAction(baseAsset hProtocol.Asset, quoteAsset hProtocol
return nil, nil
}

var output map[string]interface{}
e := networking.JSONRequest(http.DefaultClient, "GET", trade.Links.Operation.Href, "", map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("could not get operation related to trade to fetch orderAction (URL=%s): %s", trade.Links.Operation.Href, e)
}
sourceAccount, ok := output["source_account"].(string)
if !ok {
return nil, fmt.Errorf("could not cast 'source_account' to a string in the operation json result: %s (type=%T)", output["source_account"], output["source_account"])
}
sourceSellingAsset := utils.Native
sourceSellingAssetType, ok := output["selling_asset_type"].(string)
if !ok {
return nil, fmt.Errorf("could not cast 'selling_asset_type' to a string in the operation json result: %s (type=%T)", output["selling_asset_type"], output["selling_asset_type"])
}
if sourceSellingAssetType != utils.Native {
sourceSellingAssetCode, ok := output["selling_asset_code"].(string)
effectsLink := makeEffectsLink(trade)
for {
var output map[string]interface{}
e := networking.JSONRequest(http.DefaultClient, "GET", effectsLink, "", map[string]string{}, &output, "error")
if e != nil {
return nil, fmt.Errorf("could not get effect related to trade to fetch orderAction (URL=%s): %s", effectsLink, e)
}
embedded, ok := output["_embedded"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("could not cast 'selling_asset_code' to a string in the operation json result: %s (type=%T)", output["selling_asset_code"], output["selling_asset_code"])
return nil, fmt.Errorf("could not cast _embedded field in effect from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", effectsLink, output["_embedded"], output["_embedded"])
}
sourceSellingAssetIssuer, ok := output["selling_asset_issuer"].(string)
effectRecords, ok := embedded["records"].([]interface{})
if !ok {
return nil, fmt.Errorf("could not cast 'selling_asset_issuer' to a string in the operation json result: %s (type=%T)", output["selling_asset_issuer"], output["selling_asset_issuer"])
return nil, fmt.Errorf("could not cast records to a []interface{} from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", effectsLink, embedded["records"], embedded["records"])
}
if len(effectRecords) == 0 {
break
}
sourceSellingAsset = sourceSellingAssetCode + ":" + sourceSellingAssetIssuer
}

// compare the base and quote asset on the trade to what we are using as our base and quote
// then compare whether it was the base or the quote that was the seller
actionSell := model.OrderActionSell
actionBuy := model.OrderActionBuy
if sourceAccount == sdex.TradingAccount {
if sdexBaseAsset == sourceSellingAsset {
return &actionSell, nil
} else {
for i, effect := range effectRecords {
effectMap, ok := effect.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("could not cast record to a map[string]iterface{} for effect at index %d from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", i, effectsLink, effect, effect)
}

effectType, ok := effectMap["type"].(string)
if !ok {
return nil, fmt.Errorf("could not cast 'type' for effect record at index %d from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", i, effectsLink, effectMap["type"], effectMap["type"])
}
if effectType != "trade" {
continue
}

accountString, ok := effectMap["account"].(string)
if !ok {
return nil, fmt.Errorf("could not cast 'account' for effect record at index %d from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", i, effectsLink, effectMap["account"], effectMap["account"])
}
if accountString != sdex.TradingAccount {
continue
}

soldAsset, e := sdex.parseAssetFromEffect(effectMap, "sold")
if e != nil {
return nil, fmt.Errorf("could not parse asset with prefix '%s' from effect at index %d from URL when trying to fetch orderAction (URL=%s): %s", "sold", i, effectsLink, e)
}

boughtAsset, e := sdex.parseAssetFromEffect(effectMap, "bought")
if e != nil {
return nil, fmt.Errorf("could not parse asset with prefix '%s' from effect at index %d from URL when trying to fetch orderAction (URL=%s): %s", "bought", i, effectsLink, e)
}

if !(sdexBaseAsset == soldAsset && sdexQuoteAsset == boughtAsset) && !(sdexBaseAsset == boughtAsset && sdexQuoteAsset == soldAsset) {
// continue here because it could be another trade in this list of assets
// i.e. we could have multiple trades in the same path payment but we want to consider these trades individually
continue
}

// compare the base and quote asset on the trade to what we are using as our base and quote
actionSell := model.OrderActionSell
actionBuy := model.OrderActionBuy
if sdexBaseAsset == soldAsset {
return &actionSell, nil
}
return &actionBuy, nil
}

links, ok := output["_links"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("could not cast _links field in effect from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", effectsLink, output["_links"], output["_links"])
}
next, ok := links["next"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("could not cast 'next' field in effect's _links from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", effectsLink, links["next"], links["next"])
}

nextHref, ok := next["href"].(string)
if !ok {
return nil, fmt.Errorf("could not cast 'href' field in next object of effect's _links from URL when trying to fetch orderAction (URL=%s): type=%T and json=%v", effectsLink, next["href"], next["href"])
}

effectsLink = nextHref
}

// else
if sdexBaseAsset == sourceSellingAsset {
return &actionBuy, nil
} else {
return &actionSell, nil
// if we found nothing for this bot instance then return empty values so it ignores this trade
return nil, nil
}

func (sdex *SDEX) parseAssetFromEffect(effectMap map[string]interface{}, prefix string) (string, error) {
assetType := effectMap[prefix+"_asset_type"]
assetTypeString, ok := assetType.(string)
if !ok {
return "", fmt.Errorf("could not cast '%s_asset_type' to a string in the operation json result: %s (type=%T)", prefix, assetType, assetType)
}
if assetTypeString == utils.Native {
return utils.Native, nil
}

assetCode := effectMap[prefix+"_asset_code"]
assetCodeString, ok := assetCode.(string)
if !ok {
return "", fmt.Errorf("could not cast '%s_asset_code' to a string in the operation json result: %s (type=%T)", prefix, assetCode, assetCode)
}

assetIssuer := effectMap[prefix+"_asset_issuer"]
assetIssuerString, ok := assetIssuer.(string)
if !ok {
return "", fmt.Errorf("could not cast '%s_asset_issuer' to a string in the operation json result: %s (type=%T)", prefix, assetIssuer, assetIssuer)
}

return assetCodeString + ":" + assetIssuerString, nil
}

// returns tradeHistoryResult, hitCursorEnd, and any error
Expand Down

0 comments on commit fb6f4d4

Please sign in to comment.