Переглянути джерело

Merge pull request #1796 from pyth-network/chore-api-reference-refactor

(refactor:api-reference) New text.
Connor Prussin 1 рік тому
батько
коміт
5a2e4a8fb9
25 змінених файлів з 520 додано та 384 видалено
  1. 1 1
      apps/api-reference/package.json
  2. 33 20
      apps/api-reference/src/apis/evm/get-ema-price-no-older-than.ts
  3. 34 18
      apps/api-reference/src/apis/evm/get-ema-price-unsafe.ts
  4. 29 23
      apps/api-reference/src/apis/evm/get-ema-price.ts
  5. 33 19
      apps/api-reference/src/apis/evm/get-price-no-older-than.ts
  6. 35 17
      apps/api-reference/src/apis/evm/get-price-unsafe.ts
  7. 31 22
      apps/api-reference/src/apis/evm/get-price.ts
  8. 7 5
      apps/api-reference/src/apis/evm/get-update-fee.tsx
  9. 6 5
      apps/api-reference/src/apis/evm/get-valid-time-period.ts
  10. 28 19
      apps/api-reference/src/apis/evm/parse-price-feed-updates-unique.tsx
  11. 22 16
      apps/api-reference/src/apis/evm/parse-price-feed-updates.tsx
  12. 22 16
      apps/api-reference/src/apis/evm/update-price-feeds-if-necessary.tsx
  13. 18 14
      apps/api-reference/src/apis/evm/update-price-feeds.tsx
  14. 4 4
      apps/api-reference/src/components/Code/index.tsx
  15. 8 7
      apps/api-reference/src/components/Code/shiki.ts
  16. 8 0
      apps/api-reference/src/components/Code/supported-language.ts
  17. 3 2
      apps/api-reference/src/components/Code/use-highlighted-code.tsx
  18. 132 128
      apps/api-reference/src/components/EvmApi/index.tsx
  19. 3 23
      apps/api-reference/src/components/EvmApi/parameter-input.tsx
  20. 1 1
      apps/api-reference/src/components/EvmApi/run-button.tsx
  21. 0 15
      apps/api-reference/src/components/InlineCode/index.tsx
  22. 23 0
      apps/api-reference/src/components/Markdown/index.tsx
  23. 1 1
      apps/api-reference/src/components/MaxWidth/index.tsx
  24. 0 3
      apps/api-reference/src/components/Paragraph/index.tsx
  25. 38 5
      apps/api-reference/src/markdown-components.tsx

+ 1 - 1
apps/api-reference/package.json

@@ -8,7 +8,7 @@
   },
   "scripts": {
     "build": "next build",
-    "fix": "pnpm fix:format && pnpm fix:lint",
+    "fix": "pnpm fix:lint && pnpm fix:format",
     "fix:format": "prettier --write .",
     "fix:lint": "eslint --fix .",
     "pull:env": "VERCEL_ORG_ID=team_BKQrg3JJFLxZyTqpuYtIY0rj VERCEL_PROJECT_ID=prj_gbljYVzp0m5EpCuOF6nZpM4WMFM6 vercel env pull",

+ 33 - 20
apps/api-reference/src/apis/evm/get-ema-price-no-older-than.ts

@@ -6,28 +6,41 @@ export const getEmaPriceNoOlderThan = readApi<"id" | "age">({
   summary:
     "Get the exponentially weighted moving average (EMA) price object with a published timestamp from before than `age` seconds in the past.",
   description: `
-Get the latest exponentially-weighted moving average (EMA) price and confidence
-interval for the requested price feed id.  The price feed id is a 32-byte id
-written as a hexadecimal string; see the [price feed
-ids](https://pyth.network/developers/price-feed-ids) page to look up the id for
-a given symbol.  The returned price and confidence are decimal numbers written
-in the form \`a * 10^e\`, where \`e\` is an exponent included in the result.
-For example, a price of 1234 with an exponent of -2 represents the number 12.34.
-The result also includes a \`publishTime\` which is the unix timestamp for the
-price update.  The EMA methodology is described in more detail in this [blog
-post](https://pythnetwork.medium.com/whats-in-a-name-302a03e6c3e1).
+This method returns the latest price object containing **exponentially-weighted moving average** price for the requested price feed ID, if
+it has been updated sufficiently recently.
 
-The caller provides an \`age\` argument that specifies how old the price can be.
-The call reverts with a \`StalePriceError\` if the on-chain price is from more
-than \`age\` seconds in the past (with respect to the current on-chain
-timestamp).  Call [updatePriceFeeds](updatePriceFeeds) to pull a fresh price
-on-chain and solve this problem.
+The caller provides an **\`age\`** argument that specifies how old the price can be.
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update.  This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
+The price object contains the following fields:
+1. \`price\`: The latest price of the price feed.
+2. \`conf\`: The confidence level of the price feed.
+3. \`expo\`: The exponent of the price feed.
+4. \`publishtime\`: The time when the price feed was last updated.
+
+Sample \`price\` object:
+\`\`\`json
+{
+    price: 123456789n,
+    conf: 180726074n,
+    expo: -8,
+    publishTime: 1721765108n
+}
+\`\`\`
+
+The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+this case.
+
+### Error Response
+
+The above method can return the following error response:
+- \`StalePrice\`: The on-chain price has not been updated within the last
+  [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+  latest price.
+- \`PriceFeedNotFound\`: The requested price feed has never received a price
+  update or does not exist. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
   `,
   parameters: [
     {

+ 34 - 18
apps/api-reference/src/apis/evm/get-ema-price-unsafe.ts

@@ -6,26 +6,42 @@ export const getEmaPriceUnsafe = readApi<"id">({
   summary:
     "Get the **last updated** exponentially weighted moving average (EMA) price object for the requested price feed ID. _Caution: This function may return a price arbitrarily in the past_",
   description: `
-Get the latest exponentially-weighted moving average (EMA) price and confidence
-interval for the requested price feed id.  The price feed id is a 32-byte id
-written as a hexadecimal string; see the [price feed
-ids](https://pyth.network/developers/price-feed-ids) page to look up the id for
-a given symbol.  The returned price and confidence are decimal numbers written
-in the form \`a * 10^e\`, where \`e\` is an exponent included in the result.
-For example, a price of 1234 with an exponent of -2 represents the number 12.34.
-The result also includes a \`publishTime\` which is the unix timestamp for the
-price update.  The EMA methodology is described in more detail in this [blog
-post](https://pythnetwork.medium.com/whats-in-a-name-302a03e6c3e1).
+  This method returns the price object containing **last updated** exponentially-weighted moving average(EMA) price for the requested price feed ID.
 
-**This function may return a price from arbitrarily far in the past.** It is the
-caller's responsibility to check the returned \`publishTime\` to ensure that the
-update is recent enough for their use case.
+  **This function may return a price from arbitrarily far in the past.** It is the
+  caller's responsibility to check the returned \`publishTime\` to ensure that the
+  update is recent enough for their use case. If you need the latest price, update the price using [\`updatePriceFeeds()\`](updatePriceFeeds) and then call [\`getEmaPrice()\`](getEmaPrice).
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update.  This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
+  The price object contains the following fields:
+  1. \`price\`: The latest price of the price feed.
+  2. \`conf\`: The confidence level of the price feed.
+  3. \`expo\`: The exponent of the price feed.
+  4. \`publishtime\`: The time when the price feed was last updated.
+
+  Sample \`price\` object:
+  \`\`\`json
+  {
+      price: 123456789n,
+      conf: 180726074n,
+      expo: -8,
+      publishTime: 1721765108n
+  }
+  \`\`\`
+
+  The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+  mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+  this case.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`StalePrice\`: The on-chain price has not been updated within the last
+    [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+    latest price.
+  - \`PriceFeedNotFound\`: The requested price feed has never received a price
+    update or does not exist. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
   `,
   parameters: [
     {

+ 29 - 23
apps/api-reference/src/apis/evm/get-ema-price.ts

@@ -6,31 +6,37 @@ export const getEmaPrice = readApi<"id">({
   summary:
     "Get the **latest** exponentially weighted moving average (EMA) price object for the requested price feed ID.",
   description: `
-Get the latest exponentially-weighted moving average (EMA) price and confidence
-interval for the requested price feed id.  The price feed id is a 32-byte id
-written as a hexadecimal string; see the [price feed
-ids](https://pyth.network/developers/price-feed-ids) page to look up the id for
-a given symbol.  The returned price and confidence are decimal numbers written
-in the form \`a * 10^e\`, where \`e\` is an exponent included in the result.
-For example, a price of 1234 with an exponent of -2 represents the number 12.34.
-The result also includes a \`publishTime\` which is the unix timestamp for the
-price update.  The EMA methodology is described in more detail in this [blog
-post](https://pythnetwork.medium.com/whats-in-a-name-302a03e6c3e1).
+  This method returns the latest price object containing **exponentially-weighted moving average** price for the requested price feed ID.
+  The \`price\` object contains the following fields:
+  1. \`price\`: The latest **EMA** price of the price feed.
+  2. \`conf\`: The confidence level of the price feed.
+  3. \`expo\`: The exponent of the price feed.
+  4. \`publishtime\`: The time when the price feed was last updated.
 
-This function reverts with a \`StalePrice\` error if the on-chain price has not
-been updated within the last [getValidTimePeriod()](getValidTimePeriod) seconds.
-The default valid time period is set to a reasonable default on each chain and
-is typically around 1 minute.  Call [updatePriceFeeds](updatePriceFeeds) to pull
-a fresh price on-chain and solve this problem.  If you would like to configure
-the valid time period, see [getEmaPriceNoOlderThan](getEmaPriceNoOlderThan).  If
-you want the latest price regardless of when it was updated, see
-[getEmaPriceUnsafe](getEmaPriceUnsafe).
+  Sample price object:
+  \`\`\`json
+  {
+      price: 123456789n,
+      conf: 180726074n,
+      expo: -8,
+      publishTime: 1721765108n
+  }
+  \`\`\`
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update.  This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
+  The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+  mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+  this case.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`StalePrice\`: The on-chain price has not been updated within the last
+    [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+    latest price.
+  - \`PriceFeedNotFound\`: The requested price feed has never received a price
+    update or does not exist. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
   `,
   parameters: [
     {

+ 33 - 19
apps/api-reference/src/apis/evm/get-price-no-older-than.ts

@@ -6,27 +6,41 @@ export const getPriceNoOlderThan = readApi<"id" | "age">({
   summary:
     "Get the price object with a published timestamp from before than `age` seconds in the past.",
   description: `
-Get the latest price and confidence interval for the requested price feed id, if
-it has been updated sufficiently recently.  The price feed id is a 32-byte id
-written as a hexadecimal string; see the [price feed
-ids](https://pyth.network/developers/price-feed-ids) page to look up the id for
-a given symbol.  The returned price and confidence are decimal numbers written
-in the form \`a * 10^e\`, where \`e\` is an exponent included in the result.
-For example, a price of 1234 with an exponent of -2 represents the number 12.34.
-The result also includes a \`publishTime\` which is the unix timestamp for the
-price update.
+This method returns the latest price object for the requested price feed ID, if
+it has been updated sufficiently recently.
 
-The caller provides an \`age\` argument that specifies how old the price can be.
-The call reverts with a \`StalePriceError\` if the on-chain price is from more
-than \`age\` seconds in the past (with respect to the current on-chain
-timestamp).  Call [updatePriceFeeds](updatePriceFeeds) to pull a fresh price
-on-chain and solve this problem.
+The caller provides an **\`age\`** argument that specifies how old the price can be.
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update.  This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
+The price object contains the following fields:
+1. \`price\`: The latest price of the price feed.
+2. \`conf\`: The confidence level of the price feed.
+3. \`expo\`: The exponent of the price feed.
+4. \`publishtime\`: The time when the price feed was last updated.
+
+Sample \`price\` object:
+\`\`\`json
+{
+    price: 123456789n,
+    conf: 180726074n,
+    expo: -8,
+    publishTime: 1721765108n
+}
+\`\`\`
+
+The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+this case.
+
+### Error Response
+
+The above method can return the following error response:
+- \`StalePrice\`: The on-chain price has not been updated within the last
+  [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+  latest price.
+- \`PriceFeedNotFound\`: The requested price feed has never received a price
+  update or does not exist. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
   `,
   parameters: [
     {

+ 35 - 17
apps/api-reference/src/apis/evm/get-price-unsafe.ts

@@ -6,25 +6,43 @@ export const getPriceUnsafe = readApi<"id">({
   summary:
     "Get the **last updated** price object for the requested price feed ID. _Caution: This function may return a price from arbitrarily in the the past_",
   description: `
-Get the latest price and confidence interval for the requested price feed id.
-The price feed id is a 32-byte id written as a hexadecimal string; see the
-[price feed ids](https://pyth.network/developers/price-feed-ids) page to look up
-the id for a given symbol. The returned price and confidence are decimal numbers
-written in the form \`a * 10^e\`, where \`e\` is an exponent included in the
-result. For example, a price of 1234 with an exponent of -2 represents the
-number 12.34. The result also includes a \`publishTime\` which is the unix
-timestamp for the price update.
+  This method returns the price object containing **last updated** price for the requested price feed ID.
 
-**This function may return a price from arbitrarily far in the past.** It is the
-caller's responsibility to check the returned \`publishTime\` to ensure that the
-update is recent enough for their use case.
+  **This function may return a price from arbitrarily far in the past.** It is the
+  caller's responsibility to check the returned \`publishTime\` to ensure that the
+  update is recent enough for their use case. If you need the latest price, update the price using [\`updatePriceFeeds()\`](updatePriceFeeds) and then call [\`getPrice()\`](getPrice).
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update. This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
-  `,
+  The price object contains the following fields:
+  1. \`price\`: The latest price of the price feed.
+  2. \`conf\`: The confidence level of the price feed.
+  3. \`expo\`: The exponent of the price feed.
+  4. \`publishtime\`: The time when the price feed was last updated.
+
+  Sample \`price\` object:
+  \`\`\`json
+  {
+      price: 123456789n,
+      conf: 180726074n,
+      expo: -8,
+      publishTime: 1721765108n
+  }
+  \`\`\`
+
+  The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+  mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+  this case.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`StalePrice\`: The on-chain price has not been updated within the last
+    [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+    latest price.
+  - \`PriceFeedNotFound\`: The requested price feed has never received a price
+    update or does not exist. Try calling
+    [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
+`,
   parameters: [
     {
       name: "id",

+ 31 - 22
apps/api-reference/src/apis/evm/get-price.ts

@@ -5,30 +5,39 @@ export const getPrice = readApi<"id">({
   name: "getPrice",
   summary: "Get the **latest** price object for the requested price feed ID.",
   description: `
-Get the latest price and confidence interval for the requested price feed id.
-The price feed id is a 32-byte id written as a hexadecimal string; see the
-[price feed ids](https://pyth.network/developers/price-feed-ids) page to look up
-the id for a given symbol. The returned price and confidence are decimal numbers
-written in the form \`a * 10^e\`, where \`e\` is an exponent included in the
-result. For example, a price of 1234 with an exponent of -2 represents the
-number 12.34. The result also includes a \`publishTime\` which is the unix
-timestamp for the price update.
+This method returns the latest price object for the requested price feed ID.
 
-This function reverts with a \`StalePrice\` error if the on-chain price has not
-been updated within the last [getValidTimePeriod()](getValidTimePeriod)
-seconds. The default valid time period is set to a reasonable default on each
-chain and is typically around 1 minute. Call
-[updatePriceFeeds](updatePriceFeeds) to pull a fresh price on-chain and solve
-this problem. If you would like to configure the valid time period, see
-[getPriceNoOlderThan](getPriceNoOlderThan). If you want the latest price
-regardless of when it was updated, see [getPriceUnsafe](getPriceUnsafe).
+The price object contains the following fields:
+1. \`price\`: The latest price of the price feed.
+2. \`conf\`: The confidence level of the price feed.
+3. \`expo\`: The exponent of the price feed.
+4. \`publishtime\`: The time when the price feed was last updated.
 
-This function reverts with a \`PriceFeedNotFound\` error if the requested feed
-id has never received a price update. This error could either mean that the
-provided price feed id is incorrect, or (more typically) that this is the first
-attempted use of that feed on-chain. In the second case, calling
-[updatePriceFeeds](updatePriceFeeds) will solve this problem.
-  `,
+Sample \`price\` object:
+\`\`\`json
+{
+    price: 123456789n,
+    conf: 180726074n,
+    expo: -8,
+    publishTime: 1721765108n
+}
+\`\`\`
+
+The \`price\` above is in the format of \`price * 10^expo\`. So, the \`price\` in above
+mentioned sample represents the number \`123456789 * 10(-8) = 1.23456789\` in
+this case.
+
+### Error Response
+
+The above method can return the following error response:
+- \`StalePrice\`: The on-chain price has not been updated within the last
+  [\`getValidTimePeriod()\`](getValidTimePeriod) seconds. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed with the
+  latest price.
+- \`PriceFeedNotFound\`: The requested price feed has never received a price
+  update or does not exist. Try calling
+  [\`updatePriceFeeds()\`](updatePriceFeeds) to update the price feed.
+`,
   parameters: [
     {
       name: "id",

+ 7 - 5
apps/api-reference/src/apis/evm/get-update-fee.tsx

@@ -16,17 +16,19 @@ export const getUpdateFee = readApi<"updateData">({
   summary:
     "Get the fee required to update the on-chain price feeds with the provided `updateData`.",
   description: `
-Get the fee required to update the on-chain price feeds with the provided
-\`updateData\`.  The returned number of wei should be sent as the transaction
-value when calling [updatePriceFeeds](update-price-feeds).  The \`updateData\`
-can be retrieved from the [Hermes API](https://hermes.pyth.network/docs).
+  This method returns the fee required to update the on-chain price feeds for the given \`updateData\`.
+
+  The fee returned is in **wei**.
+
+  The caller should send the returned fee amount as the transaction value when calling [updatePriceFeeds](update-price-feeds).
+  The \`updateData\` can be retrieved from the [Hermes API](https://hermes.pyth.network/docs).
   `,
   parameters: [
     {
       name: "updateData",
       type: ParameterType.HexArray,
       description:
-        "The price updates that you would like to submit to [updatePriceFeeds](updatePriceFeeds).",
+        "The price updates that you would like to submit to [updatePriceFeeds](updatePriceFeeds). Fetch this data from [Hermes API](https://hermes.pyth.network/docs/#/rest/latest_price_updates).",
     },
   ],
   examples: [

+ 6 - 5
apps/api-reference/src/apis/evm/get-valid-time-period.ts

@@ -4,11 +4,12 @@ export const getValidTimePeriod = readApi<never>({
   name: "getValidTimePeriod",
   summary: "Get the default valid time period of price freshness in seconds.",
   description: `
-Get the default valid time period in seconds.  This quantity is the maximum age
-of price updates returned by functions like [getPrice](getPrice) and
-[getEmaPrice](getEmaPrice); these functions revert if the current on-chain price
-is older than this period.  The valid time period is configured to be a sane
-default for each blockchain.
+  This method returns the default valid time period of price freshness in **seconds**.
+  This quantity is the maximum age of price updates returned by functions like [getPrice](getPrice) and
+  [getEmaPrice](getEmaPrice); these functions revert if the current on-chain price
+  is older than this period.
+
+The valid time period is configured to be a same default for each blockchain.
   `,
   parameters: [],
   code: [

+ 28 - 19
apps/api-reference/src/apis/evm/parse-price-feed-updates-unique.tsx

@@ -18,32 +18,41 @@ export const parsePriceFeedUpdatesUnique = writeApi<
   summary:
     "Parse `updateData` to return the **first updated** prices if the prices are published within the given time range.",
   description: `
-Parse \`updateData\` and return the price feeds for the given \`priceIds\`
-within, if they are all **the first updates** published between
-\`minPublishTime\` and \`maxPublishTime\`.  That is to say, if \`prevPublishTime
-< minPublishTime <= publishTime <= maxPublishTime\` where \`prevPublishTime\` is
-the publish time of the previous update for the given price feed.  These updates
-are unique per \`priceId\` and \`minPublishTime\`.  This will guarantee no
-updates exist for the given \`priceIds\` earlier than the returned updates and
-still in the given time range.  If you do not need the uniqueness guarantee,
-consider using [parsePriceFeedUpdates](parse-price-feed-updates) instead.  Use
-this function if you want to use a Pyth price for a fixed time and not the most
-recent price; otherwise, consider using [updatePriceFeeds](update-price-feeds)
-followed by [getPrice](get-price) or one of its variants.  Unlike
-\`updatePriceFeeds\`, calling this function will not update the on-chain price.
+  This method parse \`updateData\` and return the price feeds for the given \`priceIds\`
+  within, if they are all **the first updates** published between \`minPublishTime\` and
+  \`maxPublishTime\`
 
-This method requires the caller to pay a fee in wei; the required fee can be
-computed by calling [getUpdateFee](get-update-fee) with \`updateData\`.
+  That is to say, if \`prevPublishTime
+  < minPublishTime <= publishTime <= maxPublishTime\` where \`prevPublishTime\` is
+  the publish time of the previous update for the given price feed.
 
-Reverts if the transferred fee is not sufficient, or \`updateData\` is invalid,
-or \`updateData\` does not contain an update for any of the given \`priceIds\`
-within the given time range.
+  These updates are unique per \`priceId\` and \`minPublishTime\`.  This will guarantee no
+  updates exist for the given \`priceIds\` earlier than the returned updates and
+  still in the given time range.  If you do not need the uniqueness guarantee,
+  consider using [parsePriceFeedUpdates](parse-price-feed-updates) instead.
+
+  Use this function if you want to use a Pyth price for a fixed time and not the most
+  recent price; otherwise, consider using [updatePriceFeeds](update-price-feeds)
+  followed by [getPrice](get-price) or one of its variants.
+
+  Unlike [updatePriceFeeds](updatePriceFeeds), calling this function will **not** update the on-chain price.
+
+  This method requires the caller to pay a fee in wei; the required fee can be
+  computed by calling [getUpdateFee](get-update-fee) with \`updateData\`.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`PriceFeedNotFoundWithinRange\`: No price feed was found within the given time range.
+  - \`InvalidUpdateData\`: The provided update data is invalid or incorrectly signed.
+  - \`InsufficientFee\`: The fee provided is less than the required fee. Try calling [getUpdateFee](getUpdateFee) to get the required fee.
   `,
   parameters: [
     {
       name: "updateData",
       type: ParameterType.HexArray,
-      description: "The price update data to parse.",
+      description:
+        "The price update data for the contract to verify. Fetch this data from [Hermes API](https://hermes.pyth.network/docs/#/rest/latest_price_updates).",
     },
     {
       name: "priceId",

+ 22 - 16
apps/api-reference/src/apis/evm/parse-price-feed-updates.tsx

@@ -18,30 +18,36 @@ export const parsePriceFeedUpdates = writeApi<
   summary:
     "Parse `updateData` to return prices if the prices are published within the given time range.",
   description: `
-Parse \`updateData\` and return the price feeds for the given \`priceIds\`
-within, if they are all published between \`minPublishTime\` and
-\`maxPublishTime\` (\`minPublishTime <= publishTime <= maxPublishTime\`).  Use
-this function if you want to use a Pyth price for a fixed time and not the most
-recent price; otherwise, consider using [updatePriceFeeds](update-price-feeds)
-followed by [getPrice](get-price) or one of its variants.  Unlike
-\`updatePriceFeeds\`, calling this function will not update the on-chain price.
+  This method parse \`updateData\` and return the price feeds for the given \`priceIds\`
+  within, if they are all published between \`minPublishTime\` and
+  \`maxPublishTime\` (\`minPublishTime <= publishTime <= maxPublishTime\`).
 
-If you need to make sure the price update is the earliest update after the
-\`minPublishTime\` consider using
-[parsePriceFeedUpdatesUnique](parse-price-feed-updates-unique).
+  Use this function if you want to use a Pyth price for a fixed time and not the most
+  recent price; otherwise, consider using [updatePriceFeeds](update-price-feeds)
+  followed by [getPrice](get-price) or one of its variants.
 
-This method requires the caller to pay a fee in wei; the required fee can be
-computed by calling [getUpdateFee](get-update-fee) with \`updateData\`.
+  Unlike [updatePriceFeeds](updatePriceFeeds), calling this function will **not** update the on-chain price.
 
-Reverts if the transferred fee is not sufficient, or \`updateData\` is invalid,
-or \`updateData\` does not contain an update for any of the given \`priceIds\`
-within the given time range.
+  If you need to make sure the price update is the earliest update after the
+  \`minPublishTime\` consider using
+  [parsePriceFeedUpdatesUnique](parse-price-feed-updates-unique).
+
+  This method requires the caller to pay a fee in wei; the required fee can be
+  computed by calling [getUpdateFee](get-update-fee) with \`updateData\`.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`PriceFeedNotFoundWithinRange\`: No price feed was found within the given time range.
+  - \`InvalidUpdateData\`: The provided update data is invalid or incorrectly signed.
+  - \`InsufficientFee\`: The fee provided is less than the required fee. Try calling [getUpdateFee](getUpdateFee) to get the required fee.
   `,
   parameters: [
     {
       name: "updateData",
       type: ParameterType.HexArray,
-      description: "The price update data to parse.",
+      description:
+        "The price update data for the contract to verify. Fetch this data from [Hermes API](https://hermes.pyth.network/docs/#/rest/latest_price_updates).",
     },
     {
       name: "priceId",

+ 22 - 16
apps/api-reference/src/apis/evm/update-price-feeds-if-necessary.tsx

@@ -18,30 +18,36 @@ export const updatePriceFeedsIfNecessary = writeApi<
   summary:
     "Update the on-chain price feeds using the provided `updateData` only if the on-chain prices are older than the valid time period.",
   description: `
-Update the on-chain price feeds using the provided \`updateData\` if the
-on-chain data is not sufficiently fresh.  The caller provides two matched
-arrays, \`priceIds\` and \`publishTimes\`.  This function applies the update if
-there exists an index \`i\` such that \`priceIds[i]\`'s last \`publishTime\` is
-before than \`publishTimes[i]\`.  Callers should typically pass
-\`publishTimes[i]\` to be equal to the publishTime of the corresponding price id
-in \`updateData\`.  If this condition is not satisfied, the call will revert
-with a \`NoFreshUpdate\` error.
+  This method updates the on-chain price feeds using the provided \`updateData\` if the on-chain data is not sufficiently fresh.
 
-This method is a variant of [updatePriceFeeds](update-price-feeds) that reduces
-gas usage when multiple callers are sending the same price updates.
 
-This function requires the caller to pay a fee to perform the update.  The
-required fee for a given set of updates can be computed by passing them to
-[getUpdateFee](get-update-fee).
+  The caller provides two matched arrays, \`priceIds\` and \`publishTimes\`.
+  This function applies the update if there exists an index \`i\` such that \`priceIds[i]\`'s last \`publishTime\` is before than \`publishTimes[i]\`.
+  Callers should typically pass \`publishTimes[i]\` to be equal to the publishTime of the corresponding price id in \`updateData\`.
 
-Reverts if the required fee is not paid, or the \`updateData\` is incorrectly
-signed or formatted.
+
+  This method is a variant of [updatePriceFeeds](update-price-feeds) that reduces
+  gas usage when multiple callers are sending the same price updates.
+
+  This function requires the caller to pay a fee to perform the update.  The
+  required fee for a given set of updates can be computed by passing them to
+  [getUpdateFee](get-update-fee).
+
+  This method returns the transaction hash of the update transaction.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`NoFreshUpdate\`: The provided update is not fresh enough to apply. It means the provided \`publishTime\` is not equal to corresponding corresponding price id in \`updateData\`.
+  - \`InvalidUpdateData\`: The provided update data is invalid or incorrectly signed.
+  - \`InsufficientFee\`: The fee provided is less than the required fee. Try calling [getUpdateFee](getUpdateFee) to get the required fee.
   `,
   parameters: [
     {
       name: "updateData",
       type: ParameterType.HexArray,
-      description: "The price update data for the contract to verify.",
+      description:
+        "The price update data for the contract to verify. Fetch this data from [Hermes API](https://hermes.pyth.network/docs/#/rest/latest_price_updates).",
     },
     {
       name: "priceId",

+ 18 - 14
apps/api-reference/src/apis/evm/update-price-feeds.tsx

@@ -15,32 +15,36 @@ export const updatePriceFeeds = writeApi<"updateData" | "fee">({
   name: "updatePriceFeeds",
   summary: "Update the on-chain price feeds using the provided `updateData`.",
   description: `
-Update the on-chain price feeds using the provided \`updateData\`, which
-contains serialized and signed price update data from Pyth Network.  You can
-retrieve the latest price \`updateData\` for a given set of price feeds from the
-[Hermes API](https://hermes.pyth.network/docs).  This function updates the
-on-chain price if the provided update is more recent than the current on-chain
-price.  Otherwise, the provided update will be ignored.  The function call will
-succeed even if the update is ignored.
+  This method updates the on-chain price feeds using the provided \`updateData\`, which contains serialized and signed price update data from Pyth Network.
+  You can retrieve the latest price \`updateData\` for a given set of price feeds from the [Hermes API](https://hermes.pyth.network/docs).
 
-This function requires the caller to pay a fee to perform the update.  The
-required fee for a given set of updates can be computed by passing them to
-[getUpdateFee](get-update-fee).
 
-Reverts if the required fee is not paid, or the \`updateData\` is incorrectly
-signed or formatted.
+  This method updates the on-chain price if the provided update is more recent than the current on-chain price. Otherwise, the provided update will be ignored. The method call will succeed even if the update is ignored.
+
+  This function requires the caller to pay a fee to perform the update.  The
+  required fee for a given set of updates can be computed by passing them to
+  [getUpdateFee](getUpdateFee).
+
+  This method returns the transaction hash of the update transaction.
+
+  ### Error Response
+
+  The above method can return the following error response:
+  - \`InvalidUpdateData\`: The provided update data is invalid or incorrectly signed.
+  - \`InsufficientFee\`: The fee provided is less than the required fee. Try calling [getUpdateFee](getUpdateFee) to get the required fee.
   `,
   parameters: [
     {
       name: "updateData",
       type: ParameterType.HexArray,
-      description: "The price update data for the contract to verify.",
+      description:
+        "The price update data for the contract to verify. Fetch this data from [Hermes API](https://hermes.pyth.network/docs/#/rest/latest_price_updates).",
     },
     {
       name: "fee",
       type: ParameterType.Int,
       description:
-        "The update fee in wei. This fee is sent as the value of the transaction.",
+        "The update fee in **wei**. This fee is sent as the value of the transaction.",
     },
   ],
   valueParam: "fee",

+ 4 - 4
apps/api-reference/src/components/Code/index.tsx

@@ -5,16 +5,16 @@ import { useMemo, useCallback, type HTMLAttributes } from "react";
 import { useEffect, useState } from "react";
 import type { OffsetOrPosition } from "shiki";
 
-import type { SupportedLanguage } from "./shiki";
 import style from "./style.module.css";
+import type { SupportedLanguage } from "./supported-language";
 import { useHighlightedCode } from "./use-highlighted-code";
 import { getLogger } from "../../browser-logger";
 import { Button } from "../Button";
 
-export type { SupportedLanguage } from "./shiki";
+export * from "./supported-language";
 
 type CodeProps = {
-  language: SupportedLanguage;
+  language?: SupportedLanguage | undefined;
   children: string;
   dimRange?: readonly [OffsetOrPosition, OffsetOrPosition] | undefined;
 };
@@ -113,7 +113,7 @@ const CopyButton = ({ children, className, ...props }: CopyButtonProps) => {
 };
 
 type HighlightedCodeProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
-  language: SupportedLanguage;
+  language?: SupportedLanguage | undefined;
   children: string;
   dimRange?: readonly [OffsetOrPosition, OffsetOrPosition] | undefined;
 };

+ 8 - 7
apps/api-reference/src/components/Code/shiki.ts

@@ -4,35 +4,36 @@ import {
   getHighlighterCore as shikiGetHighlighterCore,
 } from "shiki/core";
 import javascript from "shiki/langs/javascript.mjs";
+import json from "shiki/langs/json.mjs";
 import solidity from "shiki/langs/solidity.mjs";
 import darkPlus from "shiki/themes/dark-plus.mjs";
 import lightPlus from "shiki/themes/light-plus.mjs";
 import loadWasm from "shiki/wasm";
 
+import type { SupportedLanguage } from "./supported-language";
+
 export type Highlighter = {
   highlight: (
-    lang: SupportedLanguage,
+    lang: SupportedLanguage | undefined,
     code: string,
     options?: HighlightOptions | undefined,
   ) => string;
 };
 
-export type SupportedLanguage = "javascript" | "solidity";
-
 export type HighlightOptions = {
   decorations?: DecorationItem[] | undefined;
 };
 
 export const getHighlighter = async (): Promise<Highlighter> => {
   const highlighterCore = await shikiGetHighlighterCore({
-    langs: [javascript, solidity],
+    langs: [javascript, solidity, json],
     themes: [darkPlus, lightPlus],
     loadWasm,
   });
 
   return {
     highlight: (
-      lang: SupportedLanguage,
+      lang: SupportedLanguage | undefined,
       code: string,
       options?: HighlightOptions | undefined,
     ) => highlight(highlighterCore, lang, code, options),
@@ -41,12 +42,12 @@ export const getHighlighter = async (): Promise<Highlighter> => {
 
 const highlight = (
   highlighter: HighlighterCore,
-  lang: SupportedLanguage,
+  lang: SupportedLanguage | undefined,
   code: string,
   options?: HighlightOptions | undefined,
 ) =>
   highlighter.codeToHtml(code, {
-    lang,
+    lang: lang ?? "text",
     themes: {
       light: "light-plus",
       dark: "dark-plus",

+ 8 - 0
apps/api-reference/src/components/Code/supported-language.ts

@@ -0,0 +1,8 @@
+export const SUPPORTED_LANGUAGES = ["javascript", "solidity", "json"] as const;
+
+export type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
+
+export const isSupportedLanguage = (
+  language: string,
+): language is SupportedLanguage =>
+  (SUPPORTED_LANGUAGES as readonly string[]).includes(language);

+ 3 - 2
apps/api-reference/src/components/Code/use-highlighted-code.tsx

@@ -12,7 +12,8 @@ import {
 } from "react";
 import type { OffsetOrPosition } from "shiki";
 
-import type { Highlighter, SupportedLanguage } from "./shiki";
+import type { Highlighter } from "./shiki";
+import type { SupportedLanguage } from "./supported-language";
 import { getLogger } from "../../browser-logger";
 
 const HighlighterContext = createContext<
@@ -45,7 +46,7 @@ const useHighlighter = () => {
 };
 
 export const useHighlightedCode = (
-  language: SupportedLanguage,
+  language: SupportedLanguage | undefined,
   code: string,
   dimRange?: readonly [OffsetOrPosition, OffsetOrPosition] | undefined,
 ) => {

+ 132 - 128
apps/api-reference/src/components/EvmApi/index.tsx

@@ -23,7 +23,6 @@ import {
   useCallback,
   useMemo,
 } from "react";
-import Markdown from "react-markdown";
 import { useSwitchChain, useChainId, useConfig } from "wagmi";
 import { readContract } from "wagmi/actions";
 
@@ -32,11 +31,11 @@ import { ParameterInput } from "./parameter-input";
 import { type EvmApiType, RunButton } from "./run-button";
 import { getLogger } from "../../browser-logger";
 import { getContractAddress } from "../../evm-networks";
-import { MARKDOWN_COMPONENTS } from "../../markdown-components";
 import { useIsMounted } from "../../use-is-mounted";
 import { type SupportedLanguage, Code } from "../Code";
 import { ErrorTooltip } from "../ErrorTooltip";
 import { InlineLink } from "../InlineLink";
+import { Markdown } from "../Markdown";
 import { Select } from "../Select";
 
 export { ParameterType } from "./parameter";
@@ -127,138 +126,143 @@ export const EvmApi = <ParameterName extends string>({
   }, [chainId, chains, isMounted]);
 
   return (
-    <div className="gap-x-20 lg:grid lg:grid-cols-[2fr_1fr]">
-      <h1 className="col-span-2 mb-6 font-mono text-4xl font-medium">{name}</h1>
-      <div className="col-span-2 mb-6 opacity-60">
-        <Markdown components={MARKDOWN_COMPONENTS}>{summary}</Markdown>
+    <>
+      <h1 className="mb-6 font-mono text-4xl font-medium">{name}</h1>
+      <div className="mb-6 opacity-60">
+        <Markdown>{summary}</Markdown>
       </div>
-      <section>
-        <h2 className="mb-4 border-b border-neutral-200 text-2xl/loose font-medium dark:border-neutral-800">
-          Description
-        </h2>
-        <Markdown components={MARKDOWN_COMPONENTS}>{description}</Markdown>
-      </section>
-      <section className="flex min-w-0 flex-col">
-        <h2 className="mb-4 border-b border-neutral-200 text-2xl/loose font-medium dark:border-neutral-800">
-          Arguments
-        </h2>
-        <div className="mb-8">
-          {parameters.length > 0 ? (
-            <ul className="flex flex-col gap-4">
-              {parameters.map((parameter) => (
-                <li key={parameter.name} className="contents">
-                  <ParameterInput
-                    spec={parameter}
-                    value={paramValues[parameter.name]}
-                    setParamValues={setParamValues}
-                  />
-                </li>
-              ))}
-            </ul>
-          ) : (
-            <div className="rounded-lg bg-neutral-200 p-8 text-center text-sm dark:bg-neutral-800">
-              This API takes no arguments
-            </div>
-          )}
-        </div>
-        {examples && examples.length > 0 && (
+      <div className="grid grid-cols-1 gap-20 lg:grid-cols-[3fr_2fr] 2xl:grid-cols-[1fr_28rem]">
+        <section>
+          <h2 className="mb-4 border-b border-neutral-200 text-2xl/loose font-medium dark:border-neutral-800">
+            Description
+          </h2>
+          <Markdown>{description}</Markdown>
+        </section>
+        <section className="flex min-w-0 flex-col">
+          <h2 className="mb-4 border-b border-neutral-200 text-2xl/loose font-medium dark:border-neutral-800">
+            Arguments
+          </h2>
           <div className="mb-8">
-            <h3 className="text-sm font-semibold">Examples</h3>
-            <ul className="ml-2 text-sm">
-              {examples.map((example) => (
-                <li key={example.name}>
-                  <Example example={example} setParamValues={setParamValues} />
-                </li>
-              ))}
-            </ul>
-          </div>
-        )}
-        <Field className="mb-4 flex w-full flex-row items-center gap-2">
-          <Label className="text-sm font-bold">Network</Label>
-          <Select
-            value={currentChain}
-            onChange={({ id }) => {
-              switchChain({ chainId: id });
-            }}
-            renderButtonContents={({ id, name }) => (
-              <div className="flex h-8 grow basis-0 flex-row items-center gap-2 overflow-hidden">
-                {isMounted && (
-                  <>
-                    <ChainIcon id={id} />
-                    <div className="grow basis-0 truncate">{name}</div>
-                  </>
-                )}
-              </div>
-            )}
-            renderOption={({ id, name }) => (
-              <div key={id} className="flex flex-row items-center gap-2">
-                <ChainIcon id={id} />
-                <span>{name}</span>
+            {parameters.length > 0 ? (
+              <ul className="flex flex-col gap-4">
+                {parameters.map((parameter) => (
+                  <li key={parameter.name} className="contents">
+                    <ParameterInput
+                      spec={parameter}
+                      value={paramValues[parameter.name]}
+                      setParamValues={setParamValues}
+                    />
+                  </li>
+                ))}
+              </ul>
+            ) : (
+              <div className="rounded-lg bg-neutral-200 p-8 text-center text-sm dark:bg-neutral-800">
+                This API takes no arguments
               </div>
             )}
-            optionGroups={[
-              {
-                name: "Mainnet",
-                options: chains
-                  .filter((chain) => !chain.testnet)
-                  .sort((a, b) => a.name.localeCompare(b.name)),
-              },
-              {
-                name: "Testnet",
-                options: chains
-                  .filter((chain) => chain.testnet)
-                  .sort((a, b) => a.name.localeCompare(b.name)),
-              },
-            ]}
-            filter={(chains, value) =>
-              chains.filter((chain) =>
-                chain.name.toLowerCase().includes(value.toLowerCase()),
-              )
-            }
-            className="min-w-0 grow"
+          </div>
+          {examples && examples.length > 0 && (
+            <div className="mb-8">
+              <h3 className="text-sm font-semibold">Examples</h3>
+              <ul className="ml-2 text-sm">
+                {examples.map((example) => (
+                  <li key={example.name}>
+                    <Example
+                      example={example}
+                      setParamValues={setParamValues}
+                    />
+                  </li>
+                ))}
+              </ul>
+            </div>
+          )}
+          <Field className="mb-4 flex w-full flex-row items-center gap-2">
+            <Label className="text-sm font-bold">Network</Label>
+            <Select
+              value={currentChain}
+              onChange={({ id }) => {
+                switchChain({ chainId: id });
+              }}
+              renderButtonContents={({ id, name }) => (
+                <div className="flex h-8 grow basis-0 flex-row items-center gap-2 overflow-hidden">
+                  {isMounted && (
+                    <>
+                      <ChainIcon id={id} />
+                      <div className="grow basis-0 truncate">{name}</div>
+                    </>
+                  )}
+                </div>
+              )}
+              renderOption={({ id, name }) => (
+                <div key={id} className="flex flex-row items-center gap-2">
+                  <ChainIcon id={id} />
+                  <span>{name}</span>
+                </div>
+              )}
+              optionGroups={[
+                {
+                  name: "Mainnet",
+                  options: chains
+                    .filter((chain) => !chain.testnet)
+                    .sort((a, b) => a.name.localeCompare(b.name)),
+                },
+                {
+                  name: "Testnet",
+                  options: chains
+                    .filter((chain) => chain.testnet)
+                    .sort((a, b) => a.name.localeCompare(b.name)),
+                },
+              ]}
+              filter={(chains, value) =>
+                chains.filter((chain) =>
+                  chain.name.toLowerCase().includes(value.toLowerCase()),
+                )
+              }
+              className="min-w-0 grow"
+            />
+          </Field>
+          <RunButton
+            functionName={name}
+            parameters={parameters}
+            paramValues={paramValues}
+            {...props}
           />
-        </Field>
-        <RunButton
-          functionName={name}
-          parameters={parameters}
-          paramValues={paramValues}
-          {...props}
-        />
-      </section>
-      <TabGroup className="col-span-2 mt-24">
-        <TabList className="mb-4 flex flex-row gap-2 border-b border-neutral-200 pb-px dark:border-neutral-800">
-          {code.map(({ language }) => (
-            <Tab
-              key={LANGUAGE_TO_DISPLAY_NAME[language]}
-              className="mb-[-2px] border-b-2 border-transparent px-2 text-sm font-medium leading-loose hover:text-pythpurple-600 data-[selected]:cursor-default data-[selected]:border-pythpurple-600 data-[selected]:text-pythpurple-600 dark:hover:text-pythpurple-400 dark:data-[selected]:border-pythpurple-400 dark:data-[selected]:text-pythpurple-400"
-            >
-              {LANGUAGE_TO_DISPLAY_NAME[language]}
-            </Tab>
-          ))}
-        </TabList>
-        <TabPanels>
-          {code.map(({ code: codeContents, language, dimRange }) => (
-            <TabPanel key={LANGUAGE_TO_DISPLAY_NAME[language]}>
-              <Code
-                language={LANUGAGE_TO_SHIKI_NAME[language]}
-                dimRange={dimRange}
+        </section>
+        <TabGroup className="lg:col-span-2">
+          <TabList className="mb-4 flex flex-row gap-2 border-b border-neutral-200 pb-px dark:border-neutral-800">
+            {code.map(({ language }) => (
+              <Tab
+                key={LANGUAGE_TO_DISPLAY_NAME[language]}
+                className="mb-[-2px] border-b-2 border-transparent px-2 text-sm font-medium leading-loose hover:text-pythpurple-600 data-[selected]:cursor-default data-[selected]:border-pythpurple-600 data-[selected]:text-pythpurple-600 dark:hover:text-pythpurple-400 dark:data-[selected]:border-pythpurple-400 dark:data-[selected]:text-pythpurple-400"
               >
-                {codeContents(
-                  isMounted
-                    ? {
-                        name: currentChain.name,
-                        rpcUrl: currentChain.rpcUrls.default.http[0] ?? "",
-                        contractAddress: getContractAddress(chainId) ?? "",
-                      }
-                    : { name: "", rpcUrl: "", contractAddress: "" },
-                  paramValues,
-                )}
-              </Code>
-            </TabPanel>
-          ))}
-        </TabPanels>
-      </TabGroup>
-    </div>
+                {LANGUAGE_TO_DISPLAY_NAME[language]}
+              </Tab>
+            ))}
+          </TabList>
+          <TabPanels>
+            {code.map(({ code: codeContents, language, dimRange }) => (
+              <TabPanel key={LANGUAGE_TO_DISPLAY_NAME[language]}>
+                <Code
+                  language={LANUGAGE_TO_SHIKI_NAME[language]}
+                  dimRange={dimRange}
+                >
+                  {codeContents(
+                    isMounted
+                      ? {
+                          name: currentChain.name,
+                          rpcUrl: currentChain.rpcUrls.default.http[0] ?? "",
+                          contractAddress: getContractAddress(chainId) ?? "",
+                        }
+                      : { name: "", rpcUrl: "", contractAddress: "" },
+                    paramValues,
+                  )}
+                </Code>
+              </TabPanel>
+            ))}
+          </TabPanels>
+        </TabGroup>
+      </div>
+    </>
   );
 };
 

+ 3 - 23
apps/api-reference/src/components/EvmApi/parameter-input.tsx

@@ -12,13 +12,11 @@ import {
   type ChangeEvent,
   type Dispatch,
   type SetStateAction,
-  Fragment,
   useState,
   useCallback,
   useMemo,
   useEffect,
 } from "react";
-import Markdown from "react-markdown";
 
 import {
   type Parameter,
@@ -27,7 +25,6 @@ import {
   getValidationError,
   ParameterType,
 } from "./parameter";
-import { MARKDOWN_COMPONENTS } from "../../markdown-components";
 import {
   type PriceFeed,
   PriceFeedListContextType,
@@ -35,6 +32,7 @@ import {
 } from "../../use-price-feed-list";
 import { InlineLink } from "../InlineLink";
 import { Input } from "../Input";
+import { Markdown } from "../Markdown";
 
 type ParameterProps<ParameterName extends string> = {
   spec: Parameter<ParameterName>;
@@ -101,16 +99,7 @@ const PriceFeedIdInput = <ParameterName extends string>({
         onChange={onChangeInput}
         validationError={validationError}
         label={spec.name}
-        description={
-          <Markdown
-            components={{
-              ...MARKDOWN_COMPONENTS,
-              p: ({ children }) => <Fragment>{children}</Fragment>,
-            }}
-          >
-            {spec.description}
-          </Markdown>
-        }
+        description={<Markdown inline>{spec.description}</Markdown>}
         placeholder={PLACEHOLDERS[spec.type]}
         required={true}
       />
@@ -241,16 +230,7 @@ const DefaultParameterInput = <ParameterName extends string>({
     <Input
       validationError={validationError}
       label={spec.name}
-      description={
-        <Markdown
-          components={{
-            ...MARKDOWN_COMPONENTS,
-            p: ({ children }) => <Fragment>{children}</Fragment>,
-          }}
-        >
-          {spec.description}
-        </Markdown>
-      }
+      description={<Markdown inline>{spec.description}</Markdown>}
       placeholder={PLACEHOLDERS[spec.type]}
       required={true}
       value={internalValue}

+ 1 - 1
apps/api-reference/src/components/EvmApi/run-button.tsx

@@ -88,7 +88,7 @@ export const RunButton = <ParameterName extends string>(
       {status.type === StatusType.Results && (
         <div>
           <h3 className="mb-2 text-lg font-bold">Results</h3>
-          <Code language="javascript">{stringifyResponse(status.data)}</Code>
+          <Code language="json">{stringifyResponse(status.data)}</Code>
         </div>
       )}
       {status.type === StatusType.Error && (

+ 0 - 15
apps/api-reference/src/components/InlineCode/index.tsx

@@ -1,15 +0,0 @@
-import clsx from "clsx";
-import type { HTMLAttributes } from "react";
-
-export const InlineCode = ({
-  className,
-  ...props
-}: HTMLAttributes<HTMLElement>) => (
-  <code
-    className={clsx(
-      "whitespace-nowrap rounded-md border border-neutral-200 bg-neutral-100 px-1 py-0.5 text-[0.9em] dark:border-neutral-700 dark:bg-neutral-800",
-      className,
-    )}
-    {...props}
-  />
-);

+ 23 - 0
apps/api-reference/src/components/Markdown/index.tsx

@@ -0,0 +1,23 @@
+import { type ComponentProps, Fragment } from "react";
+import MarkdownComponent from "react-markdown";
+
+import { MARKDOWN_COMPONENTS } from "../../markdown-components";
+
+type Props = Omit<ComponentProps<typeof MarkdownComponent>, "components"> & {
+  inline?: boolean | undefined;
+};
+
+export const Markdown = ({ inline, ...props }: Props) =>
+  inline ? (
+    <MarkdownComponent
+      components={{
+        ...MARKDOWN_COMPONENTS,
+        p: ({ children }) => <Fragment>{children}</Fragment>,
+      }}
+      {...props}
+    />
+  ) : (
+    <div className="flex flex-col gap-4">
+      <MarkdownComponent components={MARKDOWN_COMPONENTS} {...props} />
+    </div>
+  );

+ 1 - 1
apps/api-reference/src/components/MaxWidth/index.tsx

@@ -1,3 +1,3 @@
 import { Styled } from "../Styled";
 
-export const MaxWidth = Styled("div", "mx-auto max-w-7xl px-8");
+export const MaxWidth = Styled("div", "mx-auto px-8");

+ 0 - 3
apps/api-reference/src/components/Paragraph/index.tsx

@@ -1,3 +0,0 @@
-import { Styled } from "../Styled";
-
-export const Paragraph = Styled("p", "mb-6 last:mb-0");

+ 38 - 5
apps/api-reference/src/markdown-components.tsx

@@ -1,12 +1,45 @@
-import { InlineCode } from "./components/InlineCode";
+import type { Components } from "react-markdown";
+
+import { Code, isSupportedLanguage } from "./components/Code";
 import { InlineLink } from "./components/InlineLink";
-import { Paragraph } from "./components/Paragraph";
 import { Styled } from "./components/Styled";
 
 export const MARKDOWN_COMPONENTS = {
   h1: Styled("h1", "mb-8 text-4xl font-medium"),
-  p: Paragraph,
   a: InlineLink,
-  code: InlineCode,
+  pre: (props) => {
+    const firstChild = props.node?.children[0];
+    if (
+      props.node?.children.length === 1 &&
+      firstChild &&
+      "tagName" in firstChild &&
+      firstChild.tagName === "code"
+    ) {
+      const { className } = firstChild.properties;
+      const className_ = Array.isArray(className) ? className[0] : className;
+      const language = /language-(\w+)/.exec(
+        typeof className_ === "string" ? className_ : "",
+      )?.[1];
+      const codeNode = firstChild.children[0];
+      return (
+        <Code
+          language={
+            language && isSupportedLanguage(language) ? language : undefined
+          }
+        >
+          {codeNode !== undefined && "value" in codeNode ? codeNode.value : ""}
+        </Code>
+      );
+    } else {
+      return <pre {...props} />;
+    }
+  },
+  code: Styled(
+    "code",
+    "whitespace-nowrap rounded-md border border-neutral-200 bg-neutral-100 px-1 py-0.5 text-[0.9em] dark:border-neutral-700 dark:bg-neutral-800",
+  ),
   strong: Styled("strong", "font-semibold"),
-};
+  ul: Styled("ul", "list-disc list-inside flex flex-col gap-1"),
+  ol: Styled("ol", "list-decimal list-inside flex flex-col gap-1"),
+  h3: Styled("h3", "text-lg font-semibold mt-4"),
+} satisfies Components;