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

Commit ef933b1

Browse files
authored
new filter: remove redundant offer updates (closes #330) (#331)
* 1 - dedupeRedundantUpdatesFilter.go and always add to submitFilters list * 2 - fix filterOps: when we keep op and new op is nil we need a second subcase for offers vs ops
1 parent 66ea610 commit ef933b1

3 files changed

Lines changed: 63 additions & 3 deletions

File tree

cmd/trade.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,9 @@ func makeBot(
387387
}
388388
submitFilters = append(submitFilters, filter)
389389
}
390+
// always add the dedupeRedundantUpdatesFilter as the second-last filter
391+
dedupeRedundantUpdatesFilter := plugins.MakeFilterDedupeRedundantUpdates(assetBase, assetQuote)
392+
submitFilters = append(submitFilters, dedupeRedundantUpdatesFilter)
390393
// exchange constraints filter is last so we catch any modifications made by previous filters. this ensures that the exchange is
391394
// less likely to reject our updates
392395
submitFilters = append(submitFilters,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package plugins
2+
3+
import (
4+
"fmt"
5+
6+
hProtocol "github.com/stellar/go/protocols/horizon"
7+
"github.com/stellar/go/txnbuild"
8+
)
9+
10+
type dedupeRedundantUpdatesFilter struct {
11+
name string
12+
baseAsset hProtocol.Asset
13+
quoteAsset hProtocol.Asset
14+
}
15+
16+
// MakeFilterDedupeRedundantUpdates makes a submit filter that dedupes offer updates that would result in the same offer being placed on the orderbook
17+
func MakeFilterDedupeRedundantUpdates(baseAsset hProtocol.Asset, quoteAsset hProtocol.Asset) SubmitFilter {
18+
return &dedupeRedundantUpdatesFilter{
19+
name: "dedupeRedundantUpdatesFilter",
20+
baseAsset: baseAsset,
21+
quoteAsset: quoteAsset,
22+
}
23+
}
24+
25+
var _ SubmitFilter = &dedupeRedundantUpdatesFilter{}
26+
27+
func (f *dedupeRedundantUpdatesFilter) Apply(ops []txnbuild.Operation, sellingOffers []hProtocol.Offer, buyingOffers []hProtocol.Offer) ([]txnbuild.Operation, error) {
28+
offersMap := map[int64]hProtocol.Offer{}
29+
for _, offer := range append(sellingOffers, buyingOffers...) {
30+
offersMap[offer.ID] = offer
31+
}
32+
33+
innerFn := func(op *txnbuild.ManageSellOffer) (*txnbuild.ManageSellOffer, bool, error) {
34+
existingOffer, hasOffer := offersMap[op.OfferID]
35+
isDupe := hasOffer && existingOffer.Amount == op.Amount && existingOffer.Price == op.Price
36+
37+
if isDupe {
38+
// do not return an op because this is spawned from an offer (hasOffer = true) and we do not want to drop the offer nor do we want to create
39+
// a new operation to delete the offer and re-update the offer to the same values, so the returned Operation is nil with keep = false
40+
return nil, false, nil
41+
}
42+
43+
// this an actual update of either the offer or a new operation, we dont want to make any changes to that so we return the original op with keep = true
44+
return op, true, nil
45+
}
46+
ops, e := filterOps(f.name, f.baseAsset, f.quoteAsset, sellingOffers, buyingOffers, ops, innerFn)
47+
if e != nil {
48+
return nil, fmt.Errorf("could not apply filter: %s", e)
49+
}
50+
51+
return ops, nil
52+
}

plugins/submitFilter.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ type SubmitFilter interface {
1919
) ([]txnbuild.Operation, error)
2020
}
2121

22-
type filterFn func(op *txnbuild.ManageSellOffer) (*txnbuild.ManageSellOffer, bool, error)
22+
type filterFn func(op *txnbuild.ManageSellOffer) (newOp *txnbuild.ManageSellOffer, keep bool, e error)
2323

2424
type filterCounter struct {
2525
idx int
@@ -306,8 +306,13 @@ func runInnerFilterFn(
306306
return newOp, nil, opCounter, &filterCounter{kept: 1}, nil
307307
}
308308
} else if isNewOpNil {
309-
// newOp will never be nil for an original offer since we will return the original non-nil offer
310-
return nil, nil, opCounter, &filterCounter{dropped: 1}, nil
309+
if originalOfferAsOp != nil {
310+
// if newOp is nil for an original offer it means we want to keep that offer.
311+
return nil, nil, offerCounter, &filterCounter{kept: 1}, nil
312+
} else {
313+
// if newOp is nil and it is not an original offer it means we want to drop the operation.
314+
return nil, nil, opCounter, &filterCounter{dropped: 1}, nil
315+
}
311316
} else {
312317
// newOp can be a transformed op to change the op to an effectively "dropped" state
313318
// prepend this so we always have delete commands at the beginning of the operation list

0 commit comments

Comments
 (0)