Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove unnecessary nesting of get order details response #64

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ using the [Trading Strategy Executor Framework](https://github.com/geniusyield/s
Thanks to the programming language agnostic RESTful API, any modern programming
language could be used to implement trading strategies and/or SOR, MMBs.

Intergration with the Genius Yield DEX has never been easier.
Integration with the Genius Yield DEX has never been easier.

> [!TIP]
> Have a look at sample configuration in [Building locally from source using the Haskell Toolchain](#building-locally-from-source-using-the-haskell-toolchain) section for thorough explanation of options made available to configure the server.

### Building locally from source using Docker

Expand Down Expand Up @@ -106,20 +109,16 @@ For details please see the following section:

```yaml
# Blockchain provider used by Atlas, our off-chain transaction building tool.
# Supported values of `coreProvider` represented as JSON for brevity:
# Local node in combination of Kupo, `{ socketPath: string, kupoUrl: string }`
# Maestro, `{ maestroToken: string, turboSubmit: boolean }`
# Blockfrost, `{ blockfrostKey: string }`
# Note that Blockfrost is not recommended as some of the operations performed aren't optimal with it.
# Head over to https://atlas-app.io/getting-started/endpoints#providing-data-provider section to know how to configure `coreProvider` and what all options are available for it.
coreProvider:
maestroToken: YOUR_MAESTRO_TOKEN
turboSubmit: false
# Network id, only `mainnet` and `preprod` are supported for at the moment.
networkId: mainnet
# Logging configuration. It's an array to cater for potentially multiple scribes.
# See it's description mentioned at https://atlas-app.io/getting-started/endpoints#providing-data-provider for more information.
logging:
- type:
# TODO: Possible values of `tag` are to be documented.
tag: stderr
# Possible values of `severity` are `Debug`, `Info`, `Warning` and `Error`.
severity: Debug
Expand Down
5 changes: 5 additions & 0 deletions geniusyield-server-lib/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Revision history for geniusyield-server-lib

## 0.4.0 -- 2024-05-20

* Fix response of GET `/v0/orders/details/{nft-token}` endpoint to not return response under a `data` field nesting.
* Added `/v0/orders/fill` endpoint.

## 0.3.0 -- 2024-05-07

* Adds TapTools OHLCV endpoint.
Expand Down
5 changes: 1 addition & 4 deletions geniusyield-server-lib/geniusyield-server-lib.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.6
name: geniusyield-server-lib
version: 0.3.0
version: 0.4.0
synopsis: GeniusYield server library
description: Library for GeniusYield server.
license: Apache-2.0
Expand Down Expand Up @@ -98,11 +98,8 @@ library
, insert-ordered-containers
, lens
, optparse-applicative
, plutus-ledger-api
, ply-core
, rio
, servant
, servant-checked-exceptions
, servant-client
, servant-client-core
, servant-foreign
Expand Down
56 changes: 44 additions & 12 deletions geniusyield-server-lib/src/GeniusYield/Server/Dex/PartialOrder.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module GeniusYield.Server.Dex.PartialOrder (
poiToOrderInfo,
PodServerException (..),
PodOrderNotFound (..),
ErrDescription (..),
) where

import Data.Aeson (ToJSON (..))
Expand Down Expand Up @@ -33,7 +32,6 @@ import RIO.Map qualified as Map
import RIO.NonEmpty qualified as NonEmpty
import RIO.Text qualified as T
import Servant
import Servant.Checked.Exceptions

-- | Number of orders that we at most allow to be filled in a single transaction.
maxFillOrders ∷ GYNatural
Expand All @@ -52,8 +50,10 @@ data PodOrderNotFound = PodOrderNotFound
deriving (Eq, Show, Generic)
deriving anyclass (Exception, ToJSON)

instance ErrStatus PodOrderNotFound where
toErrStatus _ = status404
instance Swagger.ToSchema PodOrderNotFound where
declareNamedSchema =
Swagger.genericDeclareNamedSchema Swagger.defaultSchemaOptions
& addSwaggerDescription (toErrDescription PodOrderNotFound)

class ErrDescription e where
toErrDescription ∷ e → Text
Expand Down Expand Up @@ -320,6 +320,23 @@ instance Swagger.ToSchema FillOrderParameters where
& addSwaggerDescription "Fill order(s) request parameters."
& addSwaggerExample (toJSON $ FillOrderParameters {fopAddresses = pure "addr_test1qrsuhwqdhz0zjgnf46unas27h93amfghddnff8lpc2n28rgmjv8f77ka0zshfgssqr5cnl64zdnde5f8q2xt923e7ctqu49mg5", fopChangeAddress = Just (ChangeAddress "addr_test1qrsuhwqdhz0zjgnf46unas27h93amfghddnff8lpc2n28rgmjv8f77ka0zshfgssqr5cnl64zdnde5f8q2xt923e7ctqu49mg5"), fopCollateral = Just "4293386fef391299c9886dc0ef3e8676cbdbc2c9f2773507f1f838e00043a189#1", fopOrderReferencesWithAmount = ("0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e1ea747#0", 100) :| [("0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e144444#0", 100)]})

newtype BotFillOrderParameters = BotFillOrderParameters
{ bfopOrderReferencesWithAmount ∷ NonEmpty (GYTxOutRef, GYNatural)
}
deriving stock (Show, Generic)
deriving
(FromJSON, ToJSON)
via CustomJSON '[FieldLabelModifier '[StripPrefix BotFillOrderReqPrefix, CamelToSnake]] BotFillOrderParameters

type BotFillOrderReqPrefix ∷ Symbol
type BotFillOrderReqPrefix = "bfop"

instance Swagger.ToSchema BotFillOrderParameters where
declareNamedSchema =
Swagger.genericDeclareNamedSchema Swagger.defaultSchemaOptions {Swagger.fieldLabelModifier = dropSymbolAndCamelToSnake @BotFillOrderReqPrefix}
& addSwaggerDescription "Fill order(s) request parameters specialized towards configured bot."
& addSwaggerExample (toJSON $ BotFillOrderParameters {bfopOrderReferencesWithAmount = ("0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e1ea747#0", 100) :| [("0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e144444#0", 100)]})

type FillOrderResPrefix ∷ Symbol
type FillOrderResPrefix = "fotd"

Expand All @@ -344,7 +361,7 @@ type CommonCollateralText ∷ Symbol
type CommonCollateralText = "Note that if \"collateral\" field is not provided, then framework would try to pick collateral UTxO on it's own and in that case would also be free to spend it (i.e., would be made available to coin balancer)."

type CommonSignText ∷ Symbol
type CommonSignText = "It uses the signing key from configuration to compute for wallet address. If collateral is specified in the configuration, then it would be used for."
type CommonSignText = "This endpoint would also sign & submit the built transaction. It uses the signing key from configuration to compute for wallet address. If collateral is specified in the configuration, then it would be used for."

type OrdersAPI =
Summary "Build transaction to create order"
Expand All @@ -354,7 +371,7 @@ type OrdersAPI =
:> ReqBody '[JSON] PlaceOrderParameters
:> Post '[JSON] PlaceOrderTransactionDetails
:<|> Summary "Create an order"
:> Description ("Create an order. This endpoint would also sign & submit the built transaction. " `AppendSymbol` CommonSignText `AppendSymbol` " \"stakeAddress\" field from configuration, if provided, is used to place order at a mangled address.")
:> Description ("Create an order. " `AppendSymbol` CommonSignText `AppendSymbol` " \"stakeAddress\" field from configuration, if provided, is used to place order at a mangled address.")
:> ReqBody '[JSON] BotPlaceOrderParameters
:> Post '[JSON] PlaceOrderTransactionDetails
:<|> Summary "Build transaction to cancel order(s)"
Expand All @@ -364,7 +381,7 @@ type OrdersAPI =
:> ReqBody '[JSON] CancelOrderParameters
:> Post '[JSON] CancelOrderTransactionDetails
:<|> Summary "Cancel order(s)"
:> Description ("Cancel order(s). This endpoint would also sign & submit the built transaction. " `AppendSymbol` CommonSignText)
:> Description ("Cancel order(s). " `AppendSymbol` CommonSignText)
:> ReqBody '[JSON] BotCancelOrderParameters
:> Delete '[JSON] CancelOrderTransactionDetails
:<|> Summary "Get order(s) details"
Expand All @@ -376,14 +393,18 @@ type OrdersAPI =
:> Description "Get details of an order using it's unique NFT token. Note that each order is identified uniquely by an associated NFT token which can then later be used to retrieve it's details across partial fills."
:> "details"
:> Capture "nft-token" GYAssetClass
:> Throws PodOrderNotFound
:> Get '[JSON] OrderInfoDetailed
:> UVerb 'GET '[JSON] '[WithStatus 200 OrderInfoDetailed, WithStatus 404 PodOrderNotFound]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have made a move from servant-checked-exceptions to the approach mentioned here.

:<|> Summary "Build transaction to fill order(s)"
:> Description ("Build a transaction to fill order(s). " `AppendSymbol` CommonCollateralText)
:> "tx"
:> "build-fill"
:> ReqBody '[JSON] FillOrderParameters
:> Post '[JSON] FillOrderTransactionDetails
:<|> Summary "Build transaction to fill order(s)"
:> Description ("Build a transaction to fill order(s). " `AppendSymbol` CommonSignText)
:> "fill"
:> ReqBody '[JSON] BotFillOrderParameters
:> Post '[JSON] FillOrderTransactionDetails

handleOrdersApi ∷ Ctx → ServerT OrdersAPI IO
handleOrdersApi ctx =
Expand All @@ -394,6 +415,7 @@ handleOrdersApi ctx =
:<|> handleOrdersDetails ctx
:<|> handleOrderDetails ctx
:<|> handleFillOrders ctx
:<|> handleFillOrdersAndSignSubmit ctx

handlePlaceOrder ∷ Ctx → PlaceOrderParameters → IO PlaceOrderTransactionDetails
handlePlaceOrder ctx@Ctx {..} pops@PlaceOrderParameters {..} = do
Expand Down Expand Up @@ -477,14 +499,14 @@ handleCancelOrdersAndSignSubmit ctx BotCancelOrderParameters {..} = do
-- Though transaction id would be same, but we are returning it again, just in case...
pure $ details {cotdTransactionId = txId, cotdTransaction = signedTx}

handleOrderDetails ∷ Ctx → GYAssetClass → IO (Envelope '[PodOrderNotFound] OrderInfoDetailed)
handleOrderDetails ∷ Ctx → GYAssetClass → IO (Union '[WithStatus 200 OrderInfoDetailed, WithStatus 404 PodOrderNotFound])
handleOrderDetails ctx@Ctx {..} ac = do
logInfo ctx $ "Getting order details for NFT token: " +|| ac ||+ ""
let porefs = dexPORefs ctxDexInfo
os ← runQuery ctx $ fmap poiToOrderInfoDetailed <$> orderByNft porefs ac
case os of
Nothing → throwIO PodOrderNotFound
Just o → pureSuccEnvelope o
Nothing → throwIO PodOrderNotFound -- We could use `respond` here as well but then as it would not have @application/json@ header, it would not be caught by our @errorJsonWrapMiddleware@.
Just o → respond (WithStatus @200 o)

handleOrdersDetails ∷ Ctx → [GYAssetClass] → IO [OrderInfoDetailed]
handleOrdersDetails ctx@Ctx {..} acs = do
Expand Down Expand Up @@ -539,3 +561,13 @@ handleFillOrders ctx@Ctx {..} fops@FillOrderParameters {..} = do
takerFee =
Map.foldlWithKey' (\acc ac amt → acc <> valueSingleton ac (roundFunctionForPOCVersion overallPocVersion $ toRational amt * rationalToGHC takerFeeRatio)) mempty takerACWithAmt
in takerFee

handleFillOrdersAndSignSubmit ∷ Ctx → BotFillOrderParameters → IO FillOrderTransactionDetails
handleFillOrdersAndSignSubmit ctx BotFillOrderParameters {..} = do
logInfo ctx "Filling order(s) and signing & submitting the transaction."
ctxAddr ← addressToBech32 <$> resolveCtxAddr ctx
details ← handleFillOrders ctx $ FillOrderParameters {fopAddresses = pure ctxAddr, fopChangeAddress = Just (ChangeAddress ctxAddr), fopCollateral = ctxCollateral ctx, fopOrderReferencesWithAmount = bfopOrderReferencesWithAmount}
signedTx ← handleTxSign ctx $ fotdTransaction details
txId ← handleTxSubmit ctx signedTx
-- Though transaction id would be same, but we are returning it again, just in case...
pure $ details {fotdTransactionId = txId, fotdTransaction = signedTx}
15 changes: 0 additions & 15 deletions geniusyield-server-lib/src/GeniusYield/Server/Orphans.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,11 @@ import Control.Lens (at, (?~))
import Data.HashMap.Strict.InsOrd qualified as IOHM
import Data.Swagger
import GeniusYield.Server.Auth (APIKeyAuthProtect, apiKeyHeaderText)
import GeniusYield.Server.Dex.PartialOrder (ErrDescription (..))
import RIO
import Servant
import Servant.Checked.Exceptions
import Servant.Foreign
import Servant.Swagger

type IsErr err = (ErrDescription err, ErrStatus err)

instance (IsErr err, HasSwagger sub) ⇒ HasSwagger (Throws err :> sub) where
toSwagger _ =
toSwagger (Proxy ∷ Proxy sub)
& setResponseWith
(\old _ → addDescription old)
(fromEnum $ toErrStatus (undefined ∷ err))
(return $ mempty & description .~ errDescription)
where
addDescription = description %~ ((errDescription <> " OR ") <>)
errDescription = toErrDescription (undefined ∷ err)

instance HasSwagger api ⇒ HasSwagger (APIKeyAuthProtect :> api) where
toSwagger _ =
toSwagger (Proxy ∷ Proxy api)
Expand Down
66 changes: 65 additions & 1 deletion web/swagger/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ definitions:
required:
- order_references
type: object
BotFillOrderParameters:
description: Fill order(s) request parameters specialized towards configured bot.
example:
order_references_with_amount:
- - 0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e1ea747#0
- '100'
- - 0018dbaa1611531b9f11a31765e8abe875f9c43750b82b5f321350f31e144444#0
- '100'
properties:
order_references_with_amount:
items:
items:
- $ref: '#/definitions/GYTxOutRef'
- $ref: '#/definitions/GYNatural'
maxItems: 2
minItems: 2
type: array
minItems: 1
type: array
required:
- order_references_with_amount
type: object
BotPlaceOrderParameters:
description: Place order request parameters specialized towards configured bot.
properties:
Expand Down Expand Up @@ -478,6 +500,11 @@ definitions:
- order_ref
- nft_token
type: object
PodOrderNotFound:
description: Order not found
enum:
- PodOrderNotFound
type: string
Settings:
description: Genius Yield Server settings.
properties:
Expand Down Expand Up @@ -957,14 +984,51 @@ paths:
description: Forbidden - The API key does not have permission to perform
the request
'404':
description: Order not found
description: ''
schema:
$ref: '#/definitions/PodOrderNotFound'
'500':
description: Internal server error
security:
- api-key: []
summary: Get order details
tags:
- Orders
/v0/orders/fill:
post:
consumes:
- application/json;charset=utf-8
description: Build a transaction to fill order(s). This endpoint would also
sign & submit the built transaction. It uses the signing key from configuration
to compute for wallet address. If collateral is specified in the configuration,
then it would be used for.
parameters:
- in: body
name: body
required: true
schema:
$ref: '#/definitions/BotFillOrderParameters'
produces:
- application/json;charset=utf-8
responses:
'200':
description: ''
schema:
$ref: '#/definitions/FillOrderTransactionDetails'
'400':
description: Invalid `body`
'401':
description: Unauthorized access - API key missing
'403':
description: Forbidden - The API key does not have permission to perform
the request
'500':
description: Internal server error
security:
- api-key: []
summary: Build transaction to fill order(s)
tags:
- Orders
/v0/orders/tx/build-cancel:
post:
consumes:
Expand Down
Loading