@@ -174,6 +174,11 @@ export interface FetchOrderBookParams {
174174 /** Outcome side: 'yes' or 'no'. Required for exchanges like Limitless
175175 * where the API returns a single orderbook per market. */
176176 side ?: 'yes' | 'no' ;
177+ /** Outcome alias: 'yes' or 'no', or an outcome token ID. When set,
178+ * the first argument is treated as a market ID and this value selects
179+ * which outcome's order book to fetch. Accepts the literal strings
180+ * 'yes'/'no' (resolved via a market lookup) or a raw outcome token ID. */
181+ outcome ?: string ;
177182 /** Unix timestamp (ms) — fetch a historical snapshot at or before this
178183 * time, or the start of a range when combined with `until` (hosted API only). */
179184 since ?: number ;
@@ -816,6 +821,75 @@ export abstract class PredictionMarketExchange {
816821 return markets [ 0 ] ;
817822 }
818823
824+ private cacheMarketLookup ( market : UnifiedMarket ) : void {
825+ this . markets [ market . marketId ] = market ;
826+ if ( market . slug ) {
827+ this . marketsBySlug [ market . slug ] = market ;
828+ }
829+ }
830+
831+ private marketMatchesIdentifier ( market : UnifiedMarket , id : string ) : boolean {
832+ return market . marketId === id
833+ || market . slug === id
834+ || market . contractAddress === id
835+ || ( market as any ) . id === id ;
836+ }
837+
838+ private getCachedMarketForOutcomeAlias ( id : string ) : UnifiedMarket | undefined {
839+ const direct = this . markets [ id ] ?? this . marketsBySlug [ id ] ;
840+ if ( direct && this . marketMatchesIdentifier ( direct , id ) ) return direct ;
841+ return Object . values ( this . markets ) . find ( ( market ) => this . marketMatchesIdentifier ( market , id ) ) ;
842+ }
843+
844+ private async fetchMarketForOutcomeAlias ( id : string ) : Promise < UnifiedMarket > {
845+ const cached = this . getCachedMarketForOutcomeAlias ( id ) ;
846+ if ( cached ) return cached ;
847+
848+ for ( const params of [ { marketId : id } , { slug : id } ] ) {
849+ const markets = await this . fetchMarkets ( params ) ;
850+ const exact = markets . find ( ( market ) => this . marketMatchesIdentifier ( market , id ) ) ;
851+ const market = exact ?? ( markets . length === 1 ? markets [ 0 ] : undefined ) ;
852+ if ( market ) {
853+ this . cacheMarketLookup ( market ) ;
854+ return market ;
855+ }
856+ }
857+
858+ throw new MarketNotFound ( id , this . name ) ;
859+ }
860+
861+ /**
862+ * Resolve an outcome alias ('yes'/'no') to an actual outcome token ID.
863+ * When params.outcome is set, treats `id` as a market ID, looks up the
864+ * market, and returns the resolved outcome token ID plus cleaned params.
865+ * When params.outcome is already a token ID (not 'yes'/'no'), returns it
866+ * directly. When params.outcome is not set, returns `id` unchanged.
867+ */
868+ protected async resolveOutcomeAlias (
869+ id : string ,
870+ params ?: FetchOrderBookParams ,
871+ ) : Promise < { outcomeId : string ; params ?: FetchOrderBookParams } > {
872+ if ( ! params ?. outcome ) return { outcomeId : id , params } ;
873+
874+ const outcome = String ( params . outcome ) ;
875+ const alias = outcome . toLowerCase ( ) ;
876+ const { outcome : _ , ...rest } = params ;
877+
878+ if ( alias === 'yes' || alias === 'no' ) {
879+ const market = await this . fetchMarketForOutcomeAlias ( id ) ;
880+ const selected = alias === 'yes' ? market . yes : market . no ;
881+ if ( ! selected ) {
882+ throw new Error (
883+ `Market "${ id } " has no '${ alias } ' outcome on ${ this . name } ` ,
884+ ) ;
885+ }
886+ return { outcomeId : selected . outcomeId , params : rest } ;
887+ }
888+
889+ // outcome is already a raw token ID — use it directly
890+ return { outcomeId : outcome , params : rest } ;
891+ }
892+
819893 // ----------------------------------------------------------------------------
820894 // Implementation methods (to be overridden by exchanges)
821895 // ----------------------------------------------------------------------------
0 commit comments