|
11 | 11 |
|
12 | 12 | import { InvalidSignature } from "./hosted-errors"; |
13 | 13 | import { to6dec } from "./hosted-mappers"; |
14 | | -import { TypedData } from "./signers"; |
| 14 | +import { TypedData, loadEthers } from "./signers"; |
15 | 15 |
|
16 | 16 | // The constants module is updated in a parallel-agent change to add these |
17 | 17 | // allowlists. We import them at runtime so we don't hard-fail if the change |
@@ -508,24 +508,43 @@ function validateOpinionMarketId( |
508 | 508 | message: Record<string, unknown>, |
509 | 509 | buildResponse: any, |
510 | 510 | ): void { |
511 | | - const expected = firstPresent( |
| 511 | + // The current trading-API Opinion message schema does not embed |
| 512 | + // opinion_market_id — the signed economic identity is the outcome |
| 513 | + // tokenId. Validate that against the build response's resolved token. |
| 514 | + // The legacy opinion_market_id check only applies when the message |
| 515 | + // actually carries the field (older API versions). |
| 516 | + const expectedToken = firstPresent( |
| 517 | + getPath(buildResponse, "resolved", "token_id"), |
| 518 | + getPath(buildResponse, "resolved", "tokenId"), |
| 519 | + getField(buildResponse, "token_id"), |
| 520 | + getField(buildResponse, "tokenId"), |
| 521 | + ); |
| 522 | + const actualToken = firstPresent( |
| 523 | + getField(message, "tokenId"), |
| 524 | + getField(message, "token_id"), |
| 525 | + ); |
| 526 | + if (actualToken === MISSING) economicFail("message.tokenId missing"); |
| 527 | + if (expectedToken !== MISSING && idValue(actualToken) !== idValue(expectedToken)) { |
| 528 | + economicFail(`tokenId expected ${expectedToken} got ${actualToken}`); |
| 529 | + } |
| 530 | + |
| 531 | + const actualMarketId = firstPresent( |
| 532 | + getField(message, "opinion_market_id"), |
| 533 | + getField(message, "opinionMarketId"), |
| 534 | + ); |
| 535 | + if (actualMarketId === MISSING) return; // current schema: tokenId-only message |
| 536 | + |
| 537 | + const expectedMarketId = firstPresent( |
512 | 538 | getPath(buildResponse, "resolved", "opinion_market_id"), |
513 | 539 | getPath(buildResponse, "resolved", "opinionMarketId"), |
514 | 540 | getField(buildResponse, "opinion_market_id"), |
515 | 541 | getField(buildResponse, "opinionMarketId"), |
516 | 542 | getPath(buildResponse, "params", "opinion_market_id"), |
517 | 543 | getPath(buildResponse, "params", "opinionMarketId"), |
518 | 544 | ); |
519 | | - if (expected === MISSING) economicFail("resolved.opinion_market_id missing"); |
520 | | - |
521 | | - const actual = firstPresent( |
522 | | - getField(message, "opinion_market_id"), |
523 | | - getField(message, "opinionMarketId"), |
524 | | - ); |
525 | | - if (actual === MISSING) economicFail("message.opinion_market_id missing"); |
526 | | - |
527 | | - if (idValue(actual) !== idValue(expected)) { |
528 | | - economicFail(`opinion_market_id expected ${expected} got ${actual}`); |
| 545 | + if (expectedMarketId === MISSING) economicFail("resolved.opinion_market_id missing"); |
| 546 | + if (idValue(actualMarketId) !== idValue(expectedMarketId)) { |
| 547 | + economicFail(`opinion_market_id expected ${expectedMarketId} got ${actualMarketId}`); |
529 | 548 | } |
530 | 549 | } |
531 | 550 |
|
@@ -575,12 +594,11 @@ export function verifySignature( |
575 | 594 |
|
576 | 595 | let ethers: any; |
577 | 596 | try { |
578 | | - // eslint-disable-next-line @typescript-eslint/no-require-imports |
579 | | - ethers = require("ethers"); |
580 | | - } catch { |
| 597 | + ethers = loadEthers("ethers is required for hosted signature verification"); |
| 598 | + } catch (err) { |
581 | 599 | throw new InvalidSignature( |
582 | 600 | 0, |
583 | | - "ethers is required for hosted signature verification", |
| 601 | + err instanceof Error ? err.message : "ethers is required for hosted signature verification", |
584 | 602 | ); |
585 | 603 | } |
586 | 604 |
|
|
0 commit comments