Conversation
|
|
There was a problem hiding this comment.
Pull request overview
Adds first-class support for “order matcher” services to the Anchor resolver ecosystem, including an HTTP server implementation, a discovery/consumption client, shared types/validators, and tests.
Changes:
- Introduces an Order Matcher HTTP server exposing price-info/history/depth endpoints and producing resolver metadata.
- Adds an Order Matcher client that discovers providers via the resolver and calls the advertised endpoints with runtime response validation.
- Extends the central resolver schema + lookup logic to support
services.orderMatcherand token-pair-based filtering.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/order-matcher/server.ts | New HTTP server for order matcher endpoints + service metadata generation |
| src/services/order-matcher/server.test.ts | Verifies endpoints and metadata exposure |
| src/services/order-matcher/common.ts | Shared response/metadata types and typia runtime guards |
| src/services/order-matcher/client.ts | Provider discovery + endpoint invocation client |
| src/services/order-matcher/client.test.ts | End-to-end resolver + client integration test |
| src/lib/resolver.ts | Adds orderMatcher to metadata schema, search criteria, and resolver lookup |
| src/client/index.ts | Exposes Order Matcher client through the main client entrypoint |
| throw(new Error('Missing grouping query parameter')); | ||
| } | ||
|
|
||
| const grouping = Number.parseFloat(groupingParam); |
There was a problem hiding this comment.
grouping is parsed with Number.parseFloat, which accepts inputs like "100abc" and will silently coerce them to 100. If the API intends to require a strictly numeric query value, use Number(groupingParam) (or validate with a numeric regex) so trailing garbage is rejected and clients get a consistent error.
| const grouping = Number.parseFloat(groupingParam); | |
| const grouping = Number(groupingParam); |
| routes['GET /api/price-info/:tokens'] = async (urlParams) => { | ||
| const pair = parseTokenParameter(urlParams); | ||
| const response = await getPairInfo(pair); | ||
| return({ | ||
| output: JSON.stringify(response), | ||
| contentType: 'application/json' | ||
| }); |
There was a problem hiding this comment.
Unlike the other handlers, the getPairInfo route doesn’t guard against an undefined handler result. If an implementation accidentally returns undefined, JSON.stringify(undefined) yields undefined and the HTTP server response generation can break (output is expected to be a string/Buffer). Add the same response === undefined check used by the other endpoints (or enforce via a runtime assert).
| throw(new Error(`Expected "pairs" to be an Valuizable, got ${typeof pairsUnrealized}`)); | ||
| } | ||
| // XXX:TODO: Perform deeper validation of the "pairs" structure | ||
| await pairsUnrealized('array'); |
There was a problem hiding this comment.
assertResolverLookupOrderMatcherResult validates operations and pairs, but does not validate the required matchingAccounts field for an order matcher service. This can let malformed metadata through the resolver and later fail in order-matcher/client.ts when it calls serviceInfo.matchingAccounts('array'). Add a presence/type check for matchingAccounts similar to how other services validate required fields (and ensure it’s a Valuizable array of strings).
| await pairsUnrealized('array'); | |
| await pairsUnrealized('array'); | |
| if (!('matchingAccounts' in input)) { | |
| throw(new Error('Expected "matchingAccounts" key in order matcher service, but it was not found')); | |
| } | |
| const matchingAccountsUnrealized = input.matchingAccounts; | |
| // eslint-disable-next-line @typescript-eslint/no-use-before-define | |
| if (!Metadata.isValuizable(matchingAccountsUnrealized)) { | |
| throw(new Error(`Expected "matchingAccounts" to be an Valuizable, got ${typeof matchingAccountsUnrealized}`)); | |
| } | |
| // XXX:TODO: Perform deeper validation of the "matchingAccounts" structure | |
| await matchingAccountsUnrealized('array'); |
| function assertValidOperationsOrderMatcher(input: unknown): asserts input is { operations: ToValuizableObject<NonNullable<ServiceMetadata['services']['orderMatcher']>[string]>['operations'] } { | ||
| /* XXX:TODO: Validate the specific operations */ | ||
| assertValidOperationsBanking(input); | ||
| } |
There was a problem hiding this comment.
assertValidOperationsOrderMatcher delegates to assertValidOperationsBanking, whose error message currently says "Expected "operations" key in KYC service". With order matcher using this helper too, missing/invalid operations metadata will now report an incorrect service name. Consider making the operations validator generic (e.g., accept a serviceName parameter) or adding an order-matcher-specific wrapper that throws an order-matcher-specific message before/after calling the shared validation logic.
| * Fetch price depth for a given token pair | ||
| * @param pair The pair to fetch depth for | ||
| * @param grouping The grouping to fetch the depth in, as an integer representing the price in pair[0] (the base token) | ||
| * @returns The price depth buckets with volume for the pair, priced in pair[0] (the base token) | ||
| */ | ||
| async getPairDepth(pair: TokenPairInput, grouping: number): Promise<KeetaOrderMatcherPairDepthResponse> { | ||
| const operationFactory = await this.serviceInfo.operations.getPairDepth; | ||
| if (operationFactory === undefined) { | ||
| throw(new Error('Service getPairDepth does not exist')); | ||
| } | ||
|
|
||
| if (!Number.isFinite(grouping) || grouping <= 0) { | ||
| throw(new Error('Grouping must be a positive numeric value')); | ||
| } |
There was a problem hiding this comment.
The JSDoc says grouping is "an integer", but the implementation accepts any positive finite number (and the server parses with parseFloat). Either tighten validation to integers (e.g., Number.isInteger) or update the doc comment to reflect that non-integer groupings are allowed.



This PR adds support for "order matcher" services to be in the resolver.
These services are intended to listen to the network, and once two orders that satisfy one-another are seen, it will match them against each-other and (optionally) take a fee specified by the user.