-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
44a66c7
commit 584112f
Showing
16 changed files
with
345 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,5 @@ __debug_* | |
*Key.txt | ||
address.txt | ||
coverage.out | ||
.venv | ||
.venv | ||
.makerc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/orbs-network/order-book/data/evmrepo" | ||
"github.com/orbs-network/order-book/data/redisrepo" | ||
"github.com/orbs-network/order-book/service" | ||
"github.com/redis/go-redis/v9" | ||
) | ||
|
||
var defaultDuration = 10 * time.Second | ||
|
||
func main() { | ||
redisAddress, found := os.LookupEnv("REDIS_URL") | ||
if !found { | ||
panic("REDIS_URL not set") | ||
} | ||
|
||
opt, err := redis.ParseURL(redisAddress) | ||
if err != nil { | ||
panic(fmt.Errorf("failed to parse redis url: %v", err)) | ||
} | ||
|
||
log.Printf("Redis address: %s", opt.Addr) | ||
|
||
rpcUrl, found := os.LookupEnv("RPC_URL") | ||
if !found { | ||
panic("RPC_URL not set") | ||
} | ||
|
||
rdb := redis.NewClient(opt) | ||
|
||
repository, err := redisrepo.NewRedisRepository(rdb) | ||
if err != nil { | ||
log.Fatalf("error creating repository: %v", err) | ||
} | ||
|
||
ethClient, err := ethclient.Dial(rpcUrl) | ||
if err != nil { | ||
log.Fatalf("error creating eth client: %v", err) | ||
} | ||
defer ethClient.Close() | ||
|
||
evmRepo, err := evmrepo.NewEvmRepository(ethClient) | ||
if err != nil { | ||
log.Fatalf("error creating evm repository: %v", err) | ||
} | ||
|
||
evmClient, err := service.NewEvmSvc(repository, evmRepo) | ||
if err != nil { | ||
log.Fatalf("error creating evm client: %v", err) | ||
} | ||
|
||
envDurationStr := os.Getenv("TICKER_DURATION") | ||
|
||
tickerDuration, err := time.ParseDuration(envDurationStr) | ||
if err != nil || envDurationStr == "" { | ||
fmt.Printf("Invalid or missing TICKER_DURATION. Using default of %s\n", defaultDuration) | ||
tickerDuration = defaultDuration | ||
} | ||
|
||
ticker := time.NewTicker(tickerDuration) | ||
defer ticker.Stop() | ||
|
||
ctx := context.Background() | ||
|
||
for range ticker.C { | ||
err := evmClient.CheckPendingTxs(ctx) | ||
if err != nil { | ||
log.Printf("error checking pending txs: %v", err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package redisrepo | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/google/uuid" | ||
"github.com/orbs-network/order-book/models" | ||
"github.com/orbs-network/order-book/utils/logger" | ||
"github.com/orbs-network/order-book/utils/logger/logctx" | ||
) | ||
|
||
// ProcessCompletedSwapOrders stores the updated swap orders and removes the swap from Redis. It should be called after a swap is completed. | ||
// | ||
// `orders` should be the orders that were part of the swap (with `SizePending` and `SizeFilled` updated accordingly) | ||
// | ||
// `isSuccessful` should be `true` if the swap was successful, `false` otherwise | ||
func (r *redisRepository) ProcessCompletedSwapOrders(ctx context.Context, orders []*models.Order, swapId uuid.UUID, isSuccessful bool) error { | ||
// --- START TRANSACTION --- | ||
transaction := r.client.TxPipeline() | ||
|
||
// 1. Store updated swap orders, handle completely filled orders | ||
if isSuccessful { | ||
for _, order := range orders { | ||
if order.IsFilled() { | ||
if err := storeFilledOrderTx(ctx, transaction, order); err != nil { | ||
logctx.Error(ctx, "failed to store filled order in Redis", logger.Error(err), logger.String("orderId", order.Id.String())) | ||
return fmt.Errorf("failed to store filled order in Redis: %v", err) | ||
} | ||
} else { | ||
if err := storeOrderTX(ctx, transaction, order); err != nil { | ||
logctx.Error(ctx, "failed to store open order in Redis", logger.Error(err), logger.String("orderId", order.Id.String())) | ||
return fmt.Errorf("failed to store open order in Redis: %v", err) | ||
} | ||
} | ||
} | ||
} else { | ||
// Store updated orders | ||
for _, order := range orders { | ||
if err := storeOrderTX(ctx, transaction, order); err != nil { | ||
logctx.Error(ctx, "failed to store open order in Redis", logger.Error(err), logger.String("orderId", order.Id.String())) | ||
return fmt.Errorf("failed to store open order in Redis: %v", err) | ||
} | ||
} | ||
} | ||
|
||
// 2. Remove the swap | ||
swapKey := CreateSwapKey(swapId) | ||
transaction.Del(ctx, swapKey).Err() | ||
|
||
// --- END TRANSACTION --- | ||
_, err := transaction.Exec(ctx) | ||
if err != nil { | ||
logctx.Error(ctx, "failed to execute ProcessCompletedSwapOrders transaction", logger.Error(err)) | ||
return fmt.Errorf("failed to execute ProcessCompletedSwapOrders transaction: %v", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package redisrepo | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
"time" | ||
|
||
"github.com/go-redis/redismock/v9" | ||
"github.com/google/uuid" | ||
"github.com/orbs-network/order-book/mocks" | ||
"github.com/orbs-network/order-book/models" | ||
"github.com/redis/go-redis/v9" | ||
"github.com/shopspring/decimal" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestRedisRepo_ProcessCompletedSwapOrders(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
db, mock := redismock.NewClientMock() | ||
|
||
repo := &redisRepository{ | ||
client: db, | ||
} | ||
|
||
swapId := uuid.MustParse("00000000-0000-0000-0000-000000000007") | ||
timestamp := time.Date(2023, 10, 10, 12, 0, 0, 0, time.UTC) | ||
|
||
t.Run("should process successful swap with completely filled order and partially filled order", func(t *testing.T) { | ||
|
||
filledOrder := models.Order{ | ||
SizeFilled: decimal.NewFromFloat(100), | ||
Size: decimal.NewFromFloat(100), | ||
Side: models.SELL, | ||
Timestamp: timestamp, | ||
} | ||
|
||
partiallyFilledOrder := models.Order{ | ||
SizeFilled: decimal.NewFromFloat(50), | ||
Size: decimal.NewFromFloat(100), | ||
Side: models.SELL, | ||
Timestamp: timestamp, | ||
} | ||
|
||
mock.ExpectTxPipeline() | ||
|
||
// Store completely filled order | ||
mock.ExpectZRem(CreateUserOpenOrdersKey(filledOrder.UserId), filledOrder.Id.String()).SetVal(1) | ||
mock.ExpectZAdd(CreateUserFilledOrdersKey(filledOrder.UserId), redis.Z{ | ||
Score: float64(timestamp.UTC().UnixNano()), | ||
Member: filledOrder.Id.String(), | ||
}).SetVal(1) | ||
mock.ExpectZRem(CreateSellSidePricesKey(filledOrder.Symbol), filledOrder.Id.String()).SetVal(1) | ||
mock.ExpectHSet(CreateOrderIDKey(filledOrder.Id), filledOrder.OrderToMap()).SetVal(1) | ||
|
||
// Store partially filled order | ||
mock.ExpectZAdd(CreateUserOpenOrdersKey(partiallyFilledOrder.UserId), redis.Z{ | ||
Score: float64(timestamp.UTC().UnixNano()), | ||
Member: partiallyFilledOrder.Id.String(), | ||
}).SetVal(1) | ||
mock.ExpectHSet(CreateOrderIDKey(partiallyFilledOrder.Id), partiallyFilledOrder.OrderToMap()).SetVal(1) | ||
mock.ExpectSet(CreateClientOIDKey(partiallyFilledOrder.ClientOId), partiallyFilledOrder.Id.String(), 0).SetVal("OK") | ||
f64Price, _ := partiallyFilledOrder.Price.Float64() | ||
timestamp := float64(partiallyFilledOrder.Timestamp.UTC().UnixNano()) / 1e9 | ||
score := f64Price + (timestamp / 1e12) | ||
mock.ExpectZAdd(CreateSellSidePricesKey(partiallyFilledOrder.Symbol), redis.Z{ | ||
Score: score, | ||
Member: partiallyFilledOrder.Id.String(), | ||
}).SetVal(1) | ||
|
||
// Remove swap | ||
mock.ExpectDel(CreateSwapKey(swapId)).SetVal(1) | ||
|
||
mock.ExpectTxPipelineExec() | ||
|
||
err := repo.ProcessCompletedSwapOrders(ctx, []*models.Order{&filledOrder, &partiallyFilledOrder}, swapId, true) | ||
assert.NoError(t, err) | ||
}) | ||
|
||
t.Run("should process failed swap", func(t *testing.T) { | ||
orderToBeRolledback := models.Order{ | ||
SizeFilled: decimal.NewFromFloat(20), | ||
Size: decimal.NewFromFloat(100), | ||
SizePending: decimal.NewFromFloat(0), | ||
Side: models.SELL, | ||
Timestamp: timestamp, | ||
} | ||
|
||
mock.ExpectTxPipeline() | ||
|
||
// Store order | ||
mock.ExpectZAdd(CreateUserOpenOrdersKey(orderToBeRolledback.UserId), redis.Z{ | ||
Score: float64(timestamp.UTC().UnixNano()), | ||
Member: orderToBeRolledback.Id.String(), | ||
}).SetVal(1) | ||
mock.ExpectHSet(CreateOrderIDKey(orderToBeRolledback.Id), orderToBeRolledback.OrderToMap()).SetVal(1) | ||
mock.ExpectSet(CreateClientOIDKey(orderToBeRolledback.ClientOId), orderToBeRolledback.Id.String(), 0).SetVal("OK") | ||
f64Price, _ := orderToBeRolledback.Price.Float64() | ||
timestamp := float64(orderToBeRolledback.Timestamp.UTC().UnixNano()) / 1e9 | ||
score := f64Price + (timestamp / 1e12) | ||
mock.ExpectZAdd(CreateSellSidePricesKey(orderToBeRolledback.Symbol), redis.Z{ | ||
Score: score, | ||
Member: orderToBeRolledback.Id.String(), | ||
}).SetVal(1) | ||
|
||
// Remove swap | ||
mock.ExpectDel(CreateSwapKey(swapId)).SetVal(1) | ||
|
||
mock.ExpectTxPipelineExec() | ||
|
||
err := repo.ProcessCompletedSwapOrders(ctx, []*models.Order{&orderToBeRolledback}, swapId, false) | ||
assert.NoError(t, err) | ||
}) | ||
|
||
t.Run("no database writes should happen if part of transaction fails", func(t *testing.T) { | ||
|
||
mock.ExpectTxPipeline() | ||
mock.ExpectZAdd(CreateUserOpenOrdersKey(mocks.Order.UserId), redis.Z{ | ||
Score: float64(timestamp.UTC().UnixNano()), | ||
Member: mocks.Order.Id.String(), | ||
}).SetErr(assert.AnError) | ||
|
||
err := repo.ProcessCompletedSwapOrders(ctx, []*models.Order{&mocks.Order}, swapId, true) | ||
assert.ErrorContains(t, err, "failed to execute ProcessCompletedSwapOrders transaction") | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.