diff --git a/e2e/maker/main.py b/e2e/maker/main.py index 215e001..6589b7e 100644 --- a/e2e/maker/main.py +++ b/e2e/maker/main.py @@ -6,6 +6,7 @@ import requests from orbs_orderbook import CreateOrderInput, OrderBookSDK, OrderSigner +from orbs_orderbook.exceptions import ErrApiRequest IS_DISABLED = os.environ.get("IS_DISABLED", "false").lower() == "true" BASE_URL = os.environ.get("BASE_URL", "http://localhost") @@ -35,8 +36,8 @@ class Client: def update_orders(self, price): try: self.ob_sdk.cancel_all_orders() - except requests.exceptions.HTTPError as e: - if e.response.status_code == 404: + except ErrApiRequest as e: + if e.status_code == 404: print("No orders to cancel") else: print("Error cancelling orders:", e) @@ -58,16 +59,16 @@ def update_orders(self, price): size=str(cur_size), side="sell", symbol=TICKER_SYMBOL, - clientOrderId=str(uuid4()), + client_order_id=str(uuid4()), ) - signature, message_data = self.signer.prepare_and_sign_order(order_input) + signature, message = self.signer.prepare_and_sign_order(order_input) try: self.ob_sdk.create_order( order_input=order_input, signature=signature, - message_data=message_data, + message=message, ) except Exception as e: print("Error creating sell order:", e) @@ -92,16 +93,16 @@ def update_orders(self, price): size=str(cur_size), side="buy", symbol=TICKER_SYMBOL, - clientOrderId=str(uuid4()), + client_order_id=str(uuid4()), ) - signature, message_data = self.signer.prepare_and_sign_order(order_input) + signature, message = self.signer.prepare_and_sign_order(order_input) try: self.ob_sdk.create_order( order_input=order_input, signature=signature, - message_data=message_data, + message=message, ) except Exception as e: print("Error creating buy order:", e) diff --git a/e2e/maker/requirements.txt b/e2e/maker/requirements.txt index 23d32a9..98fe6ff 100644 --- a/e2e/maker/requirements.txt +++ b/e2e/maker/requirements.txt @@ -1,2 +1,2 @@ -orbs-orderbook-sdk==0.4.0 +orbs-orderbook-sdk==0.6.0 requests==2.31.0 \ No newline at end of file diff --git a/e2e/tests/maker_endpoints_test.py b/e2e/tests/maker_endpoints_test.py index 052edc9..6173214 100644 --- a/e2e/tests/maker_endpoints_test.py +++ b/e2e/tests/maker_endpoints_test.py @@ -9,6 +9,7 @@ import pytest from orbs_orderbook import CreateOrderInput, OrderBookSDK, OrderSigner +from orbs_orderbook.exceptions import ErrApiRequest BASE_URL = os.environ.get("BASE_URL", "http://localhost") PRIVATE_KEY = os.environ.get( @@ -22,9 +23,8 @@ SIZE = "40" -# TODO 1: Update Python SDK to support get supported tokens and get filled orders for user -# TODO 2: Add test for get market depth -# TODO 3: Add different test scenaries (eg. different failed states) +# TODO 1: Add test for get market depth +# TODO 2: Add different test scenaries (eg. different failed states) @pytest.fixture @@ -42,7 +42,11 @@ def ob_signer(ob_client): @pytest.fixture(autouse=True, scope="function") def cancel_all_orders(ob_client, ob_signer): - ob_client.cancel_all_orders() + try: + ob_client.cancel_all_orders() + except Exception: + print("No orders to cancel") + pass @pytest.fixture @@ -52,16 +56,16 @@ def create_new_orders(ob_client, ob_signer, cancel_all_orders): size=SIZE, symbol=SYMBOL, side="sell", - clientOrderId=CLIENT_OID, + client_order_id=CLIENT_OID, ) - signature, message_data = ob_signer.prepare_and_sign_order(order_input) + signature, message = ob_signer.prepare_and_sign_order(order_input) yield [ ob_client.create_order( order_input=order_input, signature=signature, - message_data=message_data, + message=message, ) ] @@ -72,18 +76,18 @@ def test_create_order_success(ob_client, ob_signer): size="40", symbol="MATIC-USDC", side="sell", - clientOrderId=CLIENT_OID, + client_order_id=CLIENT_OID, ) - signature, message_data = ob_signer.prepare_and_sign_order(order_input) + signature, message = ob_signer.prepare_and_sign_order(order_input) res = ob_client.create_order( order_input=order_input, signature=signature, - message_data=message_data, + message=message, ) - assert "orderId" in res, "Order was not created" + assert res.order_id, "Order was not created" def test_create_order_fails_with_same_clientoid( @@ -94,64 +98,66 @@ def test_create_order_fails_with_same_clientoid( size="40", symbol="MATIC-USDC", side="sell", - clientOrderId=CLIENT_OID, + client_order_id=CLIENT_OID, ) - signature, message_data = ob_signer.prepare_and_sign_order(order_input) + signature, message = ob_signer.prepare_and_sign_order(order_input) - res = ob_client.create_order( - order_input=order_input, - signature=signature, - message_data=message_data, - ) + with pytest.raises(ErrApiRequest) as e: + ob_client.create_order( + order_input=order_input, + signature=signature, + message=message, + ) assert ( - res["error"] == "Conflict" + e.value.status_code == 409 ), "Order was created when it should have been rejected due to same clientOrderId" def test_cancel_order_by_oid(ob_client, ob_signer, create_new_orders): - new_oid = create_new_orders[0]["orderId"] - + new_oid = create_new_orders[0].order_id res = ob_client.cancel_order_by_id(new_oid) - assert res["orderId"] == new_oid, "Order was not cancelled by orderId" + assert res.order_id == new_oid, "Order was not cancelled by orderId" def test_cancel_order_by_oid_fails_when_cancelling_same_order( ob_client, ob_signer, create_new_orders ): - new_oid = create_new_orders[0]["orderId"] + new_oid = create_new_orders[0].order_id success = ob_client.cancel_order_by_id(new_oid) - assert success["orderId"] == new_oid, "Order was not cancelled by orderId" + assert success.order_id == new_oid, "Order was not cancelled by orderId" - fail = ob_client.cancel_order_by_id(new_oid) + with pytest.raises(ErrApiRequest) as e: + ob_client.cancel_order_by_id(new_oid) - assert fail["status_code"] == 404, "Order was cancelled when it should have failed" + assert e.value.status_code == 404, "Order was cancelled when it should have failed" def test_cancel_order_by_clientoid(ob_client, ob_signer, create_new_orders): - new_oid = create_new_orders[0]["orderId"] + new_oid = create_new_orders[0].order_id res = ob_client.cancel_order_by_client_id(CLIENT_OID) - assert res["orderId"] == new_oid, "Order was not cancelled by clientOrderId" + assert res.order_id == new_oid, "Order was not cancelled by clientOrderId" def test_cancel_order_by_clientoid_fails_when_cancelling_same_order( ob_client, ob_signer, create_new_orders ): - new_oid = create_new_orders[0]["orderId"] + new_oid = create_new_orders[0].order_id success = ob_client.cancel_order_by_client_id(CLIENT_OID) - assert success["orderId"] == new_oid, "Order was not cancelled by clientOrderId" + assert success.order_id == new_oid, "Order was not cancelled by clientOrderId" - fail = ob_client.cancel_order_by_client_id(CLIENT_OID) + with pytest.raises(ErrApiRequest) as e: + ob_client.cancel_order_by_client_id(CLIENT_OID) - assert fail["status_code"] == 404, "Order was cancelled when it should have failed" + assert e.value.status_code == 404, "Order was cancelled when it should have failed" def test_get_symbols(ob_client): @@ -163,38 +169,38 @@ def test_get_symbols(ob_client): def test_get_order_by_id(ob_client, ob_signer, create_new_orders): - new_oid = create_new_orders[0]["orderId"] + new_oid = create_new_orders[0].order_id res = ob_client.get_order_by_id(new_oid) - assert res["orderId"] == new_oid, "Order was not returned by orderId" - assert res["clientOrderId"] == CLIENT_OID, "Order was not returned by clientOrderId" - assert res["price"] == "0.865", "Order was not returned by price" - assert res["size"] == SIZE, "Order was not returned by size" - assert res["side"] == "sell", "Order was not returned by side" - assert res["symbol"] == SYMBOL, "Order was not returned by symbol" + assert res.order_id == new_oid, "Order was not returned by orderId" + assert res.client_order_id == CLIENT_OID, "Order was not returned by clientOrderId" + assert res.price == "0.865", "Order was not returned by price" + assert res.size == SIZE, "Order was not returned by size" + assert res.side == "sell", "Order was not returned by side" + assert res.symbol == SYMBOL, "Order was not returned by symbol" def test_get_order_by_clientoid(ob_client, ob_signer, create_new_orders): - new_oid = create_new_orders[0]["orderId"] + new_oid = create_new_orders[0].order_id res = ob_client.get_order_by_client_id(CLIENT_OID) - assert res["orderId"] == new_oid, "Order was not returned by orderId" - assert res["clientOrderId"] == CLIENT_OID, "Order was not returned by clientOrderId" - assert res["price"] == "0.865", "Order was not returned by price" - assert res["size"] == SIZE, "Order was not returned by size" - assert res["side"] == "sell", "Order was not returned by side" - assert res["symbol"] == SYMBOL, "Order was not returned by symbol" + assert res.order_id == new_oid, "Order was not returned by orderId" + assert res.client_order_id == CLIENT_OID, "Order was not returned by clientOrderId" + assert res.price == "0.865", "Order was not returned by price" + assert res.size == SIZE, "Order was not returned by size" + assert res.side == "sell", "Order was not returned by side" + assert res.symbol == SYMBOL, "Order was not returned by symbol" def test_get_orders_for_user(ob_client, ob_signer, create_new_orders): res = ob_client.get_orders_for_user(page=1, page_size=25) - assert len(res["data"]) > 0, "No orders returned" - assert "orderId" in res["data"][0], "orderId not returned" - assert "clientOrderId" in res["data"][0], "clientOrderId not returned" - assert "price" in res["data"][0], "price not returned" - assert "size" in res["data"][0], "size not returned" - assert "side" in res["data"][0], "side not returned" - assert "symbol" in res["data"][0], "symbol not returned" + assert len(res.data) > 0, "No orders returned" + assert res.data[0]["orderId"], "orderId not returned" + assert res.data[0]["clientOrderId"], "clientOrderId not returned" + assert res.data[0]["price"], "price not returned" + assert res.data[0]["size"], "size not returned" + assert res.data[0]["side"], "side not returned" + assert res.data[0]["symbol"], "symbol not returned" diff --git a/e2e/tests/requirements.txt b/e2e/tests/requirements.txt index 9bd05a4..4b64b3d 100644 --- a/e2e/tests/requirements.txt +++ b/e2e/tests/requirements.txt @@ -1,2 +1,2 @@ -orbs-orderbook-sdk==0.4.0 +orbs-orderbook-sdk==0.6.0 pytest==7.4.4 \ No newline at end of file diff --git a/models/order.go b/models/order.go index 591a390..7ff6cd8 100644 --- a/models/order.go +++ b/models/order.go @@ -14,8 +14,10 @@ import ( // EIP712 signature components type Signature struct { - Eip712Sig string `json:"eip712Sig"` - Eip712MsgData map[string]interface{} `json:"eip712MsgData"` + Eip712Sig string `json:"eip712Sig"` + Eip712Domain map[string]interface{} `json:"eip712Domain"` + Eip712MsgTypes map[string]interface{} `json:"eip712MsgTypes"` + Eip712Msg map[string]interface{} `json:"eip712Msg"` } type Order struct { @@ -35,21 +37,30 @@ type Order struct { func (o *Order) OrderToMap() map[string]string { // error can be ignored here because we know the data is valid - eip712MsgDataBytes, _ := json.Marshal(o.Signature.Eip712MsgData) - eip712MsgDataStr := string(eip712MsgDataBytes) + eip712MsgBytes, _ := json.Marshal(o.Signature.Eip712Msg) + eip712MsgStr := string(eip712MsgBytes) + + eip712DomainBytes, _ := json.Marshal(o.Signature.Eip712Domain) + eip712DomainStr := string(eip712DomainBytes) + + eip712MsgTypesBytes, _ := json.Marshal(o.Signature.Eip712MsgTypes) + eip712MsgTypesStr := string(eip712MsgTypesBytes) + return map[string]string{ - "id": o.Id.String(), - "clientOId": o.ClientOId.String(), - "userId": o.UserId.String(), - "price": o.Price.String(), - "symbol": o.Symbol.String(), - "size": o.Size.String(), - "sizePending": o.SizePending.String(), - "sizeFilled": o.SizeFilled.String(), - "side": o.Side.String(), - "timestamp": o.Timestamp.Format(time.RFC3339), - "eip712Sig": o.Signature.Eip712Sig, - "eip712MsgData": eip712MsgDataStr, + "id": o.Id.String(), + "clientOId": o.ClientOId.String(), + "userId": o.UserId.String(), + "price": o.Price.String(), + "symbol": o.Symbol.String(), + "size": o.Size.String(), + "sizePending": o.SizePending.String(), + "sizeFilled": o.SizeFilled.String(), + "side": o.Side.String(), + "timestamp": o.Timestamp.Format(time.RFC3339), + "eip712Sig": o.Signature.Eip712Sig, + "eip712Domain": eip712DomainStr, + "eip712MsgTypes": eip712MsgTypesStr, + "eip712Msg": eip712MsgStr, } } @@ -103,9 +114,19 @@ func (o *Order) MapToOrder(data map[string]string) error { return fmt.Errorf("no signature provided") } - messageData, exists := data["eip712MsgData"] + eip712DomainJson, exists := data["eip712Domain"] + if !exists { + return fmt.Errorf("no eip712DomainJson provided") + } + + eipMsgTypesJson, exists := data["eip712MsgTypes"] if !exists { - return fmt.Errorf("no messageData provided") + return fmt.Errorf("no eip712MsgTypes provided") + } + + eip712MsgJson, exists := data["eip712Msg"] + if !exists { + return fmt.Errorf("no eip712MsgJson provided") } sideStr, exists := data["side"] @@ -168,10 +189,22 @@ func (o *Order) MapToOrder(data map[string]string) error { return fmt.Errorf("invalid timestamp: %v", err) } - eip712MsgData := map[string]interface{}{} + eip712Msg := map[string]interface{}{} + + if err := json.Unmarshal([]byte(eip712MsgJson), &eip712Msg); err != nil { + return fmt.Errorf("invalid eip712Msg: %v", err) + } + + eip712Domain := map[string]interface{}{} + + if err := json.Unmarshal([]byte(eip712DomainJson), &eip712Domain); err != nil { + return fmt.Errorf("invalid eip712Domain: %v", err) + } + + eip712MsgTypes := map[string]interface{}{} - if err := json.Unmarshal([]byte(messageData), &eip712MsgData); err != nil { - return fmt.Errorf("invalid eip712MsgData: %v", err) + if err := json.Unmarshal([]byte(eipMsgTypesJson), &eip712MsgTypes); err != nil { + return fmt.Errorf("invalid eip712MsgTypes: %v", err) } o.Id = id @@ -183,8 +216,10 @@ func (o *Order) MapToOrder(data map[string]string) error { o.SizePending = sizePending o.SizeFilled = sizeFilled o.Signature = Signature{ - Eip712Sig: signatureStr, - Eip712MsgData: eip712MsgData, + Eip712Sig: signatureStr, + Eip712Domain: eip712Domain, + Eip712MsgTypes: eip712MsgTypes, + Eip712Msg: eip712Msg, } o.Side = side o.Timestamp = timestamp diff --git a/models/order_test.go b/models/order_test.go index d57b578..5ebbce3 100644 --- a/models/order_test.go +++ b/models/order_test.go @@ -27,29 +27,42 @@ func TestOrder_OrderToMap(t *testing.T) { SizePending: decimal.NewFromInt(400), Signature: Signature{ Eip712Sig: "signature", - Eip712MsgData: map[string]interface{}{ + Eip712Msg: map[string]interface{}{ "message": "data", }, + Eip712Domain: map[string]interface{}{ + + "version": "1", + }, + Eip712MsgTypes: map[string]interface{}{ + "EIP712Domain": []map[string]interface{}{ + { + "name": "version", + }, + }, + }, }, Side: BUY, Timestamp: timestamp, } - eip712MsgDataStr := "{\"message\":\"data\"}" + eip712MsgStr := "{\"message\":\"data\"}" expectedMap := map[string]string{ - "id": order.Id.String(), - "clientOId": order.ClientOId.String(), - "userId": order.UserId.String(), - "price": order.Price.String(), - "symbol": order.Symbol.String(), - "size": order.Size.String(), - "sizePending": order.SizePending.String(), - "sizeFilled": order.SizeFilled.String(), - "side": order.Side.String(), - "timestamp": order.Timestamp.Format(time.RFC3339), - "eip712Sig": order.Signature.Eip712Sig, - "eip712MsgData": eip712MsgDataStr, + "id": order.Id.String(), + "clientOId": order.ClientOId.String(), + "userId": order.UserId.String(), + "price": order.Price.String(), + "symbol": order.Symbol.String(), + "size": order.Size.String(), + "sizePending": order.SizePending.String(), + "sizeFilled": order.SizeFilled.String(), + "side": order.Side.String(), + "timestamp": order.Timestamp.Format(time.RFC3339), + "eip712Sig": order.Signature.Eip712Sig, + "eip712Msg": eip712MsgStr, + "eip712Domain": "{\"version\":\"1\"}", + "eip712MsgTypes": "{\"EIP712Domain\":[{\"name\":\"version\"}]}", } actualMap := order.OrderToMap() @@ -62,19 +75,21 @@ func TestOrder_MapToOrder(t *testing.T) { t.Run("when all data is provided", func(t *testing.T) { data := map[string]string{ - "id": id.String(), - "clientOId": clientOId.String(), - "userId": userId.String(), - "price": "10.99", - "symbol": "MATIC-USDC", - "size": "1000", - "sizePending": "0", - "sizeFilled": "0", - "side": "buy", - "timestamp": "2021-01-01T00:00:00Z", - "clientOrderId": id.String(), - "eip712Sig": "signature", - "eip712MsgData": "{\"message\":\"data\"}", + "id": id.String(), + "clientOId": clientOId.String(), + "userId": userId.String(), + "price": "10.99", + "symbol": "MATIC-USDC", + "size": "1000", + "sizePending": "0", + "sizeFilled": "0", + "side": "buy", + "timestamp": "2021-01-01T00:00:00Z", + "clientOrderId": id.String(), + "eip712Sig": "signature", + "eip712Msg": "{\"message\":\"data\"}", + "eip712Domain": "{\"version\":\"1\"}", + "eip712MsgTypes": "{\"EIP712Domain\":[{\"name\":\"version\"}]}", } err := order.MapToOrder(data) @@ -90,9 +105,7 @@ func TestOrder_MapToOrder(t *testing.T) { assert.Equal(t, priceDec, order.Price) assert.Equal(t, "MATIC-USDC", order.Symbol.String()) assert.Equal(t, sizeDec, order.Size) - assert.Equal(t, Signature{Eip712Sig: "signature", Eip712MsgData: map[string]interface{}{ - "message": "data", - }}, order.Signature) + assert.Equal(t, Signature{Eip712Sig: "signature", Eip712Domain: map[string]interface{}{"version": "1"}, Eip712MsgTypes: map[string]interface{}{"EIP712Domain": []interface{}{map[string]interface{}{"name": "version"}}}, Eip712Msg: map[string]interface{}{"message": "data"}}, order.Signature) assert.Equal(t, "buy", order.Side.String()) assert.Equal(t, "2021-01-01 00:00:00 +0000 UTC", order.Timestamp.String()) }) diff --git a/service/create_order.go b/service/create_order.go index 2c7ad30..7bdb1b4 100644 --- a/service/create_order.go +++ b/service/create_order.go @@ -15,14 +15,16 @@ import ( ) type CreateOrderInput struct { - UserId uuid.UUID - Price decimal.Decimal - Symbol models.Symbol - Size decimal.Decimal - Side models.Side - ClientOrderID uuid.UUID - Eip712Sig string - Eip712MsgData map[string]interface{} + UserId uuid.UUID + Price decimal.Decimal + Symbol models.Symbol + Size decimal.Decimal + Side models.Side + ClientOrderID uuid.UUID + Eip712Sig string + Eip712Domain *map[string]interface{} + Eip712MsgTypes *map[string]interface{} + Eip712Msg *map[string]interface{} } func (s *Service) CreateOrder(ctx context.Context, input CreateOrderInput) (models.Order, error) { @@ -37,7 +39,7 @@ func (s *Service) CreateOrder(ctx context.Context, input CreateOrderInput) (mode } isVerifed, err := s.blockchainClient.VerifySignature(ctx, VerifySignatureInput{ - MessageData: input.Eip712MsgData, + MessageData: *input.Eip712Msg, Signature: input.Eip712Sig, PublicKey: user.PubKey, }) @@ -93,8 +95,10 @@ func (s *Service) createNewOrder(ctx context.Context, input CreateOrderInput, us Symbol: input.Symbol, Size: input.Size, Signature: models.Signature{ - Eip712Sig: input.Eip712Sig, - Eip712MsgData: input.Eip712MsgData, + Eip712Sig: input.Eip712Sig, + Eip712Domain: *input.Eip712Domain, + Eip712MsgTypes: *input.Eip712MsgTypes, + Eip712Msg: *input.Eip712Msg, }, Side: input.Side, Timestamp: time.Now().UTC(), diff --git a/service/create_order_test.go b/service/create_order_test.go index a26355d..bb5fe8c 100644 --- a/service/create_order_test.go +++ b/service/create_order_test.go @@ -25,6 +25,10 @@ func TestService_CreateOrder(t *testing.T) { orderId := uuid.MustParse("e577273e-12de-4acc-a4f8-de7fb5b86e37") size := decimal.NewFromFloat(1000.00) + eip712Domain := map[string]interface{}{} + eip712MsgTypes := map[string]interface{}{} + eip712Msg := map[string]interface{}{} + user := models.User{ Id: userId, PubKey: userPubKey, @@ -32,14 +36,16 @@ func TestService_CreateOrder(t *testing.T) { } input := service.CreateOrderInput{ - UserId: userId, - Price: price, - Symbol: symbol, - Size: size, - Side: models.SELL, - ClientOrderID: orderId, - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + UserId: userId, + Price: price, + Symbol: symbol, + Size: size, + Side: models.SELL, + ClientOrderID: orderId, + Eip712Sig: "mock-sig", + Eip712Domain: &eip712Domain, + Eip712MsgTypes: &eip712MsgTypes, + Eip712Msg: &eip712Msg, } t.Run("no user in context - should return error", func(t *testing.T) { @@ -94,18 +100,22 @@ func TestService_CreateOrder(t *testing.T) { assert.Equal(t, newOrder.Price, price) assert.Equal(t, newOrder.Symbol, symbol) assert.Equal(t, newOrder.Size, size) - assert.Equal(t, newOrder.Signature, models.Signature{Eip712Sig: "mock-sig", Eip712MsgData: map[string]interface{}{}}) + assert.Equal(t, newOrder.Signature, models.Signature{Eip712Sig: "mock-sig", Eip712Domain: eip712Domain, Eip712MsgTypes: eip712MsgTypes, Eip712Msg: eip712Msg}) assert.Equal(t, newOrder.Side, models.SELL) }) t.Run("existing order with different userId - should return `ErrClashingOrderId` error", func(t *testing.T) { input := service.CreateOrderInput{ - UserId: userId, - Price: price, - Symbol: symbol, - Size: size, - Side: models.SELL, - ClientOrderID: orderId, + UserId: userId, + Price: price, + Symbol: symbol, + Size: size, + Side: models.SELL, + ClientOrderID: orderId, + Eip712Sig: "mock-sig", + Eip712Domain: &eip712Domain, + Eip712MsgTypes: &eip712MsgTypes, + Eip712Msg: &eip712Msg, } svc, _ := service.New(&mocks.MockOrderBookStore{User: &user, Order: &models.Order{UserId: uuid.MustParse("b577273e-12de-4acc-a4f8-de7fb5b86e37")}}, mockBcClient) @@ -118,12 +128,16 @@ func TestService_CreateOrder(t *testing.T) { t.Run("existing order with same clientOrderId - should return `ErrClashingClientOrderId` error", func(t *testing.T) { input := service.CreateOrderInput{ - UserId: userId, - Price: price, - Symbol: symbol, - Size: size, - Side: models.SELL, - ClientOrderID: orderId, + UserId: userId, + Price: price, + Symbol: symbol, + Size: size, + Side: models.SELL, + ClientOrderID: orderId, + Eip712Sig: "mock-sig", + Eip712Domain: &eip712Domain, + Eip712MsgTypes: &eip712MsgTypes, + Eip712Msg: &eip712Msg, } svc, _ := service.New(&mocks.MockOrderBookStore{User: &user, Order: &models.Order{ClientOId: orderId, UserId: userId}}, mockBcClient) diff --git a/service/evm_check_pending_txs.go b/service/evm_check_pending_txs.go index c3fc5bc..c96eda9 100644 --- a/service/evm_check_pending_txs.go +++ b/service/evm_check_pending_txs.go @@ -26,6 +26,8 @@ func (e *EvmClient) CheckPendingTxs(ctx context.Context) error { return nil } + logctx.Info(ctx, "Found pending transactions to process", logger.Int("numPending", len(pendingSwaps))) + var wg sync.WaitGroup var mu sync.Mutex diff --git a/service/evm_verify_signature.go b/service/evm_verify_signature.go index 00121e2..4c317fb 100644 --- a/service/evm_verify_signature.go +++ b/service/evm_verify_signature.go @@ -61,7 +61,7 @@ func (e *EvmClient) VerifySignature(ctx context.Context, input VerifySignatureIn // Normalize the `v` value in the signature (adjust for EVM's signature format) v := signatureBytes[64] if v == 27 || v == 28 { - logctx.Info(ctx, "signature v value is normalized", logger.String("publicKey", fullPubKey)) + logctx.Debug(ctx, "signature v value is normalized", logger.String("publicKey", fullPubKey)) v -= 27 signatureBytes[64] = v } diff --git a/transport/rest/create_order.go b/transport/rest/create_order.go index cc9f5d2..93aa62f 100644 --- a/transport/rest/create_order.go +++ b/transport/rest/create_order.go @@ -16,13 +16,15 @@ import ( ) type CreateOrderRequest struct { - Price string `json:"price"` - Size string `json:"size"` - Symbol string `json:"symbol"` - Side string `json:"side"` - ClientOrderId string `json:"clientOrderId"` - Eip712Sig string `json:"eip712Sig"` - Eip712MsgData map[string]interface{} `json:"eip712MsgData"` + Price string `json:"price"` + Size string `json:"size"` + Symbol string `json:"symbol"` + Side string `json:"side"` + ClientOrderId string `json:"clientOrderId"` + Eip712Sig string `json:"eip712Sig"` + Eip712Domain map[string]interface{} `json:"eip712Domain"` + Eip712MsgTypes map[string]interface{} `json:"eip712MsgTypes"` + Eip712Msg map[string]interface{} `json:"eip712Msg"` } type CreateOrderResponse struct { @@ -47,13 +49,15 @@ func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) { } if err := handleValidateRequiredFields(hVRFArgs{ - price: args.Price, - size: args.Size, - symbol: args.Symbol, - side: args.Side, - clientOrderId: args.ClientOrderId, - eip712Sig: args.Eip712Sig, - eip712MsgData: &args.Eip712MsgData, + price: args.Price, + size: args.Size, + symbol: args.Symbol, + side: args.Side, + clientOrderId: args.ClientOrderId, + eip712Sig: args.Eip712Sig, + eip712Msg: &args.Eip712Msg, + eip712MsgTypes: &args.Eip712MsgTypes, + eip712Domain: &args.Eip712Domain, }); err != nil { restutils.WriteJSONError(ctx, w, http.StatusBadRequest, err.Error()) return @@ -74,14 +78,16 @@ func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) { logctx.Info(ctx, "user trying to create order", logger.String("userId", user.Id.String()), logger.String("price", parsedFields.roundedDecPrice.String()), logger.String("size", parsedFields.decSize.String()), logger.String("clientOrderId", parsedFields.clientOrderId.String())) order, err := h.svc.CreateOrder(ctx, service.CreateOrderInput{ - UserId: user.Id, - Price: parsedFields.roundedDecPrice, - Symbol: parsedFields.symbol, - Size: parsedFields.decSize, - Side: parsedFields.side, - ClientOrderID: parsedFields.clientOrderId, - Eip712Sig: args.Eip712Sig, - Eip712MsgData: args.Eip712MsgData, + UserId: user.Id, + Price: parsedFields.roundedDecPrice, + Symbol: parsedFields.symbol, + Size: parsedFields.decSize, + Side: parsedFields.side, + ClientOrderID: parsedFields.clientOrderId, + Eip712Sig: args.Eip712Sig, + Eip712Domain: &args.Eip712Domain, + Eip712MsgTypes: &args.Eip712MsgTypes, + Eip712Msg: &args.Eip712Msg, }) if err == models.ErrSignatureVerificationError { @@ -134,13 +140,15 @@ func (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) { } type hVRFArgs struct { - price string - size string - symbol string - side string - clientOrderId string - eip712Sig string - eip712MsgData *map[string]interface{} + price string + size string + symbol string + side string + clientOrderId string + eip712Sig string + eip712Msg *map[string]interface{} + eip712MsgTypes *map[string]interface{} + eip712Domain *map[string]interface{} } func handleValidateRequiredFields(args hVRFArgs) error { @@ -163,8 +171,14 @@ func handleValidateRequiredFields(args hVRFArgs) error { case args.eip712Sig == "": return fmt.Errorf("missing required field 'eip712Sig'") - case args.eip712MsgData == nil || *args.eip712MsgData == nil: - return fmt.Errorf("missing required field 'eip712MsgData'") + case args.eip712Msg == nil || *args.eip712Msg == nil: + return fmt.Errorf("missing required field 'eip712Msg'") + + case args.eip712MsgTypes == nil || *args.eip712MsgTypes == nil: + return fmt.Errorf("missing required field 'eip712MsgTypes'") + + case args.eip712Domain == nil || *args.eip712Domain == nil: + return fmt.Errorf("missing required field 'eip712Domain'") default: return nil diff --git a/transport/rest/create_order_test.go b/transport/rest/create_order_test.go index ba04b21..a6a72f5 100644 --- a/transport/rest/create_order_test.go +++ b/transport/rest/create_order_test.go @@ -27,13 +27,15 @@ func createBody(t *testing.T, args rest.CreateOrderRequest) *bytes.Buffer { func TestHandler_CreateOrder(t *testing.T) { orderReq := rest.CreateOrderRequest{ - Price: "100.0", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, } orderReqJSON, _ := json.Marshal(orderReq) @@ -147,7 +149,7 @@ func TestHandler_CreateOrder(t *testing.T) { "{\"status\":400,\"msg\":\"missing required field 'eip712Sig'\"}\n", }, { - "no eip712 message data in request body - should return `missing required field 'eip712MsgData'` error", + "no eip712 message data in request body - should return `missing required field 'eip712Msg'` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ Price: "100.0", @@ -158,20 +160,22 @@ func TestHandler_CreateOrder(t *testing.T) { Eip712Sig: "mock-sig", }), http.StatusBadRequest, - "{\"status\":400,\"msg\":\"missing required field 'eip712MsgData'\"}\n", + "{\"status\":400,\"msg\":\"missing required field 'eip712Msg'\"}\n", }, // // ----- Parse fields tests ----- { "invalid price format - should return `price is not a valid number format` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0.0", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0.0", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'price' is not a valid number format\"}\n", @@ -180,13 +184,15 @@ func TestHandler_CreateOrder(t *testing.T) { "price format cannot exceed 8 decimal places - should return `price must not exceed 8 decimal places` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "0.86515197364766170000", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "0.86515197364766170000", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'price' must not exceed 8 decimal places\"}\n", @@ -195,13 +201,15 @@ func TestHandler_CreateOrder(t *testing.T) { "price format cannot exceed 8 decimal places - should return `price must not exceed 8 decimal places` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "50000.823709877", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "50000.823709877", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'price' must not exceed 8 decimal places\"}\n", @@ -210,13 +218,15 @@ func TestHandler_CreateOrder(t *testing.T) { "negative price - should return `price must be positive` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "-100.0", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "-100.0", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'price' must be positive\"}\n", @@ -225,13 +235,15 @@ func TestHandler_CreateOrder(t *testing.T) { "invalid size format - should return `size is not a valid number format` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0", - Size: "dsfdsfsdf", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "dsfdsfsdf", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'size' is not a valid number format\"}\n", @@ -240,13 +252,15 @@ func TestHandler_CreateOrder(t *testing.T) { "negative size - should return `size must be positive` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0", - Size: "-10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "-10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'size' must be positive\"}\n", @@ -255,13 +269,15 @@ func TestHandler_CreateOrder(t *testing.T) { "invalid symbol - should return `symbol is not valid` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0", - Size: "10", - Symbol: "BTC-SOME-INVALID-SYMBOL", - Side: "sell", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "10", + Symbol: "BTC-SOME-INVALID-SYMBOL", + Side: "sell", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'symbol' is not valid\"}\n", @@ -270,13 +286,15 @@ func TestHandler_CreateOrder(t *testing.T) { "invalid side - should return `side is not valid` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0", - Size: "10", - Symbol: "MATIC-USDC", - Side: "some-invalid-side", - ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "10", + Symbol: "MATIC-USDC", + Side: "some-invalid-side", + ClientOrderId: "a677273e-12de-4acc-a4f8-de7fb5b86e37", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'side' is not valid\"}\n", @@ -285,13 +303,15 @@ func TestHandler_CreateOrder(t *testing.T) { "invalid client order id - should return `clientOrderId is not valid` error", &mocks.MockOrderBookService{}, createBody(t, rest.CreateOrderRequest{ - Price: "100.0", - Size: "10", - Symbol: "MATIC-USDC", - Side: "sell", - ClientOrderId: "1", - Eip712Sig: "mock-sig", - Eip712MsgData: map[string]interface{}{}, + Price: "100.0", + Size: "10", + Symbol: "MATIC-USDC", + Side: "sell", + ClientOrderId: "1", + Eip712Sig: "mock-sig", + Eip712Domain: map[string]interface{}{}, + Eip712MsgTypes: map[string]interface{}{}, + Eip712Msg: map[string]interface{}{}, }), http.StatusBadRequest, "{\"status\":400,\"msg\":\"'clientOrderId' is not valid\"}\n", diff --git a/transport/rest/create_orders.go b/transport/rest/create_orders.go index ef0b058..4a708af 100644 --- a/transport/rest/create_orders.go +++ b/transport/rest/create_orders.go @@ -62,13 +62,15 @@ func (h *Handler) CreateOrders(w http.ResponseWriter, r *http.Request) { for _, order := range args.Orders { if err = handleValidateRequiredFields(hVRFArgs{ - price: order.Price, - size: order.Size, - symbol: args.Symbol, - side: order.Side, - clientOrderId: order.ClientOrderId, - eip712Sig: order.Eip712Sig, - eip712MsgData: &order.Eip712MsgData, + price: order.Price, + size: order.Size, + symbol: args.Symbol, + side: order.Side, + clientOrderId: order.ClientOrderId, + eip712Sig: order.Eip712Sig, + eip712Msg: &order.Eip712Msg, + eip712MsgTypes: &order.Eip712MsgTypes, + eip712Domain: &order.Eip712Domain, }); err != nil { logctx.Warn(ctx, "failed to validate required fields", logger.Error(err), logger.String("userId", user.Id.String())) response.Status = http.StatusBadRequest @@ -96,14 +98,16 @@ func (h *Handler) CreateOrders(w http.ResponseWriter, r *http.Request) { } order, err := h.svc.CreateOrder(ctx, service.CreateOrderInput{ - UserId: user.Id, - Price: parsedFields.roundedDecPrice, - Symbol: parsedFields.symbol, - Size: parsedFields.decSize, - Side: parsedFields.side, - ClientOrderID: parsedFields.clientOrderId, - Eip712Sig: order.Eip712Sig, - Eip712MsgData: order.Eip712MsgData, + UserId: user.Id, + Price: parsedFields.roundedDecPrice, + Symbol: parsedFields.symbol, + Size: parsedFields.decSize, + Side: parsedFields.side, + ClientOrderID: parsedFields.clientOrderId, + Eip712Sig: order.Eip712Sig, + Eip712Domain: &order.Eip712Domain, + Eip712MsgTypes: &order.Eip712MsgTypes, + Eip712Msg: &order.Eip712Msg, }) if err == models.ErrSignatureVerificationError { diff --git a/transport/rest/taker.go b/transport/rest/taker.go index 1c3496a..a52caf1 100644 --- a/transport/rest/taker.go +++ b/transport/rest/taker.go @@ -28,9 +28,11 @@ type BeginSwapRes struct { } type Fragment struct { - OutAmount string `json:"outAmount"` - Eip712Sig string `json:"eip712Sig"` - Eip712MsgData map[string]interface{} `json:"eip712MsgData"` + OutAmount string `json:"outAmount"` + Eip712Sig string `json:"eip712Sig"` + Eip712Domain map[string]interface{} `json:"eip712Domain"` + Eip712Msg map[string]interface{} `json:"eip712Msg"` + Eip712MsgTypes map[string]interface{} `json:"eip712MsgTypes"` } type ConfirmSwapRes struct { SwapId string `json:"swapId"` @@ -119,9 +121,11 @@ func (h *Handler) handleQuote(w http.ResponseWriter, r *http.Request, isSwap boo for i := 0; i < len(swapData.Fragments); i++ { convOutAmount := h.convertToTokenDec(r.Context(), req.OutToken, swapData.Fragments[i].Size) frag := Fragment{ - OutAmount: convOutAmount, - Eip712Sig: swapData.Orders[i].Signature.Eip712Sig, - Eip712MsgData: swapData.Orders[i].Signature.Eip712MsgData, + OutAmount: convOutAmount, + Eip712Sig: swapData.Orders[i].Signature.Eip712Sig, + Eip712Domain: swapData.Orders[i].Signature.Eip712Domain, + Eip712MsgTypes: swapData.Orders[i].Signature.Eip712MsgTypes, + Eip712Msg: swapData.Orders[i].Signature.Eip712Msg, } res.Fragments = append(res.Fragments, frag) }