diff --git a/docs/fdc/guides/fdc-by-hand.mdx b/docs/fdc/guides/fdc-by-hand.mdx new file mode 100644 index 00000000..8d860544 --- /dev/null +++ b/docs/fdc/guides/fdc-by-hand.mdx @@ -0,0 +1,465 @@ +--- +title: FDC by hand +authors: [nikerzetic, filipkoprivec] +description: Learn how to use FDC without the help of scripts. +tags: [intermediate, ethereum, fdc, hardhat] +keywords: [ethereum, flare-data-connector, evm, flare-network] +sidebar_position: 1 +--- + +import VotingRoundIdCalculator from "../../../src/components/FDC/VotingRoundIdCalculator"; +import ToHexConverter from "../../../src/components/FDC/ToHexConverter"; +import ThemedImage from "@theme/ThemedImage"; +import useBaseUrl from "@docusaurus/useBaseUrl"; + +In this guide, we will demonstrate how [FDC workflow](https://dev.flare.network/fdc/overview) can be performed almost entirely without the use of any script. +The purpose of this guide is to familiarize the reader with the FDC workflow and introduce them to tooling surrounding FDC. +This is **not** how the FDC is intended to be used. +Nonetheless, the tools described in this guide may prove useful when debugging the actual code. + +## Request data + +In this guide, we will check whether the string `rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe` is a valid XRPL testnet address. +This is an example of the `AddressValidity` attestation request. +We chose it for demonstration purposes because it requires a single input parameter, but the same process would work for any of the FDC [attestation types](https://dev.flare.network/fdc/attestation-types). + +## Preparing the request + +The FDC accepts requests as byte strings, encoded in a special way. +These can be produced manually, but an easier way to do it is through a verifier server. +A verifier server checks the validity of input data and returns an `abiEncodedRequest` that can be passed on to the FDC. + +In this guide, we will use the Flare-hosted verifier server. +Its interactive documentation is available at [the address](https://fdc-verifiers-testnet.flare.network/verifier/xrp/api-doc#/). + +The interface requires authentication; +the key `00000000-0000-0000-0000-000000000000` can be used. +To authenticate, click `Authorize` in the top right corner, and input the above key. + + + +
+
+ +
+
+ +
+
+ +Once authenticated, scroll down to the **AddressValidity** section, and expand the `/verifier/xrp/AddressValidity/prepareRequest` item. +Click on the `Try it out` button in the upper right corner of the expanded card, +and a `Request body` field will appear. + +
+
+ +
+
+ +
+
+ +Replace the `addressStr` field value with the above address `rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe`, and ensure that the form matches: + +```json title="Request body" +{ + "attestationType": "0x4164647265737356616c69646974790000000000000000000000000000000000", + "sourceId": "0x7465737458525000000000000000000000000000000000000000000000000000", + "requestBody": { + "addressStr": "r3wvdzNDkNJ3e5ut1RJfWtBxDHT9sddQRQ" + } +} +``` + + + +Then click `Execute`. +The `abiEncodedRequest` will appear under the `Response body` section below, along with the request status which should be `VALID`. + +{" "} + + + +```json title="Response body" +{ + "status": "VALID", + "abiEncodedRequest": "0x4164647265737356616c696469747900000000000000000000000000000000007465737458525000000000000000000000000000000000000000000000000000cf6de269807c522f39f90e9a84ec13993f58d5473fe918acbe6197efb5a17c2e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002272337776647a4e446b4e4a336535757431524a665774427844485439736464515251000000000000000000000000000000000000000000000000000000000000" +} +``` + +There are two additional values within the request body that we have not yet properly explained. +They are the UTF8 hex-encoded strings of `AddressValidity` and `testXRP` respectively, zero-padded to 32 bytes. +These will be different for each attestation type and source. +The full list of values is available below. + +
+ + Interactive documentation for all attestation types, and the corresponding + values for the `attestationType` and `sourceId` fields. + + - + [AddressValidity](https://dev.flare.network/fdc/attestation-types/address-validity) + - + [testBTC](https://fdc-verifiers-testnet.flare.network/verifier/btc_testnet4/api-doc#/) + - + [testXRP](https://fdc-verifiers-testnet.flare.network/verifier/xrp/api-doc#/) + - + [testDOGE](https://fdc-verifiers-testnet.flare.network/verifier/doge/api-doc#/) + - [BTC](https://fdc-verifiers-mainnet.flare.network/verifier/btc/api-doc#/) - + [XRP](https://fdc-verifiers-mainnet.flare.network/verifier/xrp/api-doc#/) - + [DOGE](https://fdc-verifiers-mainnet.flare.network/verifier/doge/api-doc#/) - + [EVMTransaction](https://dev.flare.network/fdc/attestation-types/evm-transaction) +
+ +Input the appropriate value into the encoder bellow. + + + +## Submitting the request + +We submit the attestation request to the FDC through the `FdcHub` contract. +It is one of the official Flare contracts, and it is deployed on each of the Flare chains. +We will submit the attestation request to the `FdcHub` contract on Coston2. +Either [Flare Explorer](https://coston2-explorer.flare.network/address/0x48aC463d7975828989331F4De43341627b9c5f1D) or [Flarescan](https://coston2.testnet.flarescan.com/address/0x48aC463d7975828989331F4De43341627b9c5f1D) can be used. + +First, we must navigate to the `Contract` tab on the chosen explorer, and then to `Write contract` ([Flare Explorer](https://coston2-explorer.flare.network/address/0x48aC463d7975828989331F4De43341627b9c5f1D?tab=write_contract), [Flarescan](https://coston2.testnet.flarescan.com/address/0x48aC463d7975828989331F4De43341627b9c5f1D/contract/114/writeContract)). +We can then open the `requestAttestation` function widget. +Here we input the `abiEncodedRequest` value that we received from the verifier server, as well as the fee that needs to be paid to the contract. + + + +The request fee can be queried from the `FdcRequestFeeConfigurations` contract, through its `getRequestFee` function ([Flare Explorer](https://coston2-explorer.flare.network/address/0x191a1282Ac700edE65c5B0AaF313BAcC3eA7fC7e?tab=read_contract), [Flarescan](https://coston2.testnet.flarescan.com/address/0x191a1282Ac700edE65c5B0AaF313BAcC3eA7fC7e/contract/114/readContract)). +The input parameter for this function is the `abiEncodedRequest` from the verifier server. + + + +To execute the `requestAttestation` call, we need to connect the wallet. +We input the `abiEncodedRequest` value, and the amount returned by the `getRequestFee` function. + +After the transaction has been executed successfully, we need to open it up in the explorer. +We should remember its block number for later. + +
+Links to `FdcHub` and `FdcRequestFeeConfigurations` contracts on all Flare chains. +### FdcHub + +- Coston + - [Flare Explorer](https://coston-explorer.flare.network/address/0x1c78A073E3BD2aCa4cc327d55FB0cD4f0549B55b) + - [Flarescan](https://coston.testnet.flarescan.com/address/0x1c78A073E3BD2aCa4cc327d55FB0cD4f0549B55b) +- Coston2 + - [Flare Explorer](https://coston2-explorer.flare.network/address/0x48aC463d7975828989331F4De43341627b9c5f1D) + - [Flarescan](https://coston2.testnet.flarescan.com/address/0x48aC463d7975828989331F4De43341627b9c5f1D) +- Songbird + - [Flare Explorer](https://songbird-explorer.flare.network/address/0xCfD4669a505A70c2cE85db8A1c1d14BcDE5a1a06) + - [Flarescan](https://songbird.flarescan.com/address/0xCfD4669a505A70c2cE85db8A1c1d14BcDE5a1a06) +- Flare + - [Flare Explorer](https://flare-explorer.flare.network/address/0xc25c749DC27Efb1864Cb3DADa8845B7687eB2d44) + - [Flarescan](https://flare.flarescan.com/address/0xc25c749DC27Efb1864Cb3DADa8845B7687eB2d44) + +### FdcRequestFeeConfigurations + +- Coston + - [Flare Explorer](https://coston-explorer.flare.network/address/0x2bBfb46aC3A71A6725699004B8a8fE4C928E7108) + - [Flarescan](https://coston.testnet.flarescan.com/address/0x2bBfb46aC3A71A6725699004B8a8fE4C928E7108) +- Coston2 + - [Flare Explorer](https://coston2-explorer.flare.network/address/0x191a1282Ac700edE65c5B0AaF313BAcC3eA7fC7e) + - [Flarescan](https://coston2.testnet.flarescan.com/address/0x191a1282Ac700edE65c5B0AaF313BAcC3eA7fC7e) +- Songbird + - [Flare Explorer](https://songbird-explorer.flare.network/address/0x8998a3b85350aA4CA5f55cD80ab1f7C9C0ddf02C) + - [Flarescan](https://songbird.flarescan.com/address/0x8998a3b85350aA4CA5f55cD80ab1f7C9C0ddf02C) +- Flare + - [Flare Explorer](https://flare-explorer.flare.network/address/0x259852Ae6d5085bDc0650D3887825f7b76F0c4fe) + - [Flarescan](https://flare.flarescan.com/address/0x259852Ae6d5085bDc0650D3887825f7b76F0c4fe) + +
+ +## Waiting for the voting round to finalize + +Before we can retrieve the proof and data, we must wait for the voting round in which the request was made to be finalized. +To check whether the round has been finalized, we need to know the block in which the attestation request transaction was made; +or more precisely, we need the timestamp of that block. + +We can calculate the voting round ID from the transaction timestamp using the following formula. + +$$ +\text{votingRoundId} = \frac{\text{transactionTimestamp} - \text{firsVotingRoundStartTs}}{\text{votingEpochDurationSeconds}} +$$ + +Here, the `transactionTimestamp` represents the timestamp of the transaction in which we submitted the attestation request. +The other two values are: + +$$ +\text{firsVotingRoundStartTs} = 1658430000 \qquad \text{votingEpochDurationSeconds} = 90 +$$ + +The following form calculates the round ID for you. + + + +Once we know the voting round ID, we can go to the `Finalizations` tab of the [Coston2 Systems Explorer](https://coston2-systems-explorer.flare.rocks/finalizations). +When the round has been finalized, its ID will appear on the list. + +
+ Links to all System Explorers + [Coston](https://coston-systems-explorer.flare.rocks/finalizations) - + [Coston2](https://coston2-systems-explorer.flare.rocks/finalizations) - + [Songbird](https://songbird-systems-explorer.flare.rocks/finalizations) - + [Flare](https://flare-systems-explorer.flare.rocks/finalizations) +
+ +## Preparing the proof request + +Once the round has been finalized, we can prepare the proof request using the [Flare Data Availability Client](https://ctn2-data-availability.flare.network/api-doc#/) interactive documentation. +As in the previous step, we first need to authenticate using the same API key, `00000000-0000-0000-0000-000000000000`. +We can then expand the `/api/v1/fdc/proof-by-request-round` widget, and click `Try it out`. + + + + + +We input the voting round ID of our request under the `votingRoundId` field, and the `abiEncodedRequest` under the `requestBytes` field. +Then we click on the `Execute` button. +The proof response will appear under the `Response body` section. + + + +```json title="Response body" +{ + "response": { + "attestationType": "0x4164647265737356616c69646974790000000000000000000000000000000000", + "sourceId": "0x7465737458525000000000000000000000000000000000000000000000000000", + "votingRound": 1028678, + "lowestUsedTimestamp": 18446744073709552000, + "requestBody": { + "addressStr": "r3wvdzNDkNJ3e5ut1RJfWtBxDHT9sddQRQ" + }, + "responseBody": { + "isValid": true, + "standardAddress": "r3wvdzNDkNJ3e5ut1RJfWtBxDHT9sddQRQ", + "standardAddressHash": "0x1e2adcb99103f6396903f33db1526fa66aedfbfee4405def0ef69e0fcd949f47" + } + }, + "proof": [ + "0x5422093333fabcdd137138efa611efcbb932e65184b12415d2f74d511c1f27b9", + "0x28b15d5e07d2249c7acd8b6deae1706e01be84231264bc66d99553970dbf3bde", + "0x486452aac82578f8b2b9a88df400e80a33d9945111d503f2b205d4209279f225", + "0xc7188d9db7d522ba2b9a84d7aec34745e6acde1a5118372b53aa072d1ad61894" + ] +} +``` + +The Data Availability Client informs us that the address is, indeed, a valid XRPL address. +But the above response is not entirely correct; +the timestamp is off by `385`. +This is a JavaScript rounding error. +To get the right response, we need to use the `curl` command in a terminal. + +The `curl` command is displayed as the first part of the `Responses` section. +In this case, it is: + +```sh +curl -X 'POST' \ + 'https://ctn2-data-availability.flare.network/api/v1/fdc/proof-by-request-round' \ + -H 'accept: application/json' \ + -H 'x-api-key: 00000000-0000-0000-0000-000000000000' \ + -H 'Content-Type: application/json' \ + -H 'X-CSRFTOKEN: rYJ04UxDuekdzYgChGXRIfQI904VD8qK2UtiBwZ1uMLlkAEwPgNrxvCLsNS5PdYX' \ + -d '{ + "votingRoundId": 1028678, + "requestBytes": "0x4164647265737356616c696469747900000000000000000000000000000000007465737458525000000000000000000000000000000000000000000000000000cf6de269807c522f39f90e9a84ec13993f58d5473fe918acbe6197efb5a17c2e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002272337776647a4e446b4e4a336535757431524a665774427844485439736464515251000000000000000000000000000000000000000000000000000000000000" +}' +``` + +The output of the `curl` command is then: + +```json +{ + "response": { + "attestationType": "0x4164647265737356616c69646974790000000000000000000000000000000000", + "sourceId": "0x7465737458525000000000000000000000000000000000000000000000000000", + "votingRound": 1028678, + "lowestUsedTimestamp": 18446744073709551615, + "requestBody": { + "addressStr": "r3wvdzNDkNJ3e5ut1RJfWtBxDHT9sddQRQ" + }, + "responseBody": { + "isValid": true, + "standardAddress": "r3wvdzNDkNJ3e5ut1RJfWtBxDHT9sddQRQ", + "standardAddressHash": "0x1e2adcb99103f6396903f33db1526fa66aedfbfee4405def0ef69e0fcd949f47" + } + }, + "proof": [ + "0x5422093333fabcdd137138efa611efcbb932e65184b12415d2f74d511c1f27b9", + "0x28b15d5e07d2249c7acd8b6deae1706e01be84231264bc66d99553970dbf3bde", + "0x486452aac82578f8b2b9a88df400e80a33d9945111d503f2b205d4209279f225", + "0xc7188d9db7d522ba2b9a84d7aec34745e6acde1a5118372b53aa072d1ad61894" + ] +} +``` + +
+ Links to all Data Availability Clients + [Coston](https://ctn-data-availability.flare.network/api-doc#/) - + [Coston2](https://ctn2-data-availability.flare.network/api-doc#/) - + [Songbird](https://sgb-data-availability.flare.network/api-doc#/) - + [Flare](https://flr-data-availability.flare.network/api-doc#/) +
+ +## Verifying the data + +The last thing remaining is to verify the proof returned by the Data Availability Client. +We do so through the `FdcVerification` contract ([Flare Explorer](https://coston2-explorer.flare.network/address/0x075bf301fF07C4920e5261f93a0609640F53487D?tab=read_write_contract) [Flarescan](https://coston2.testnet.flarescan.com/address/0x075bf301fF07C4920e5261f93a0609640F53487D/contract/114/readContract)). + + + +We input the above `Response body` data as parameters to the `verifyAddressValidity` function of the `FdcVerification` contract. +When we `Read` the function, we get back `true`, which means that the proof is valid. + +
+ Links to `FdcVerification` contract on all Flare chains.- + Coston - [Flare + Explorer](https://coston-explorer.flare.network/address/0x57a2db68fb40f6C61342FF4beF283AE185eA8E51) + - + [Flarescan](https://coston.testnet.flarescan.com/address/0x57a2db68fb40f6C61342FF4beF283AE185eA8E51) + - Coston2 - [Flare + Explorer](https://coston2-explorer.flare.network/address/0x075bf301fF07C4920e5261f93a0609640F53487D) + - + [Flarescan](https://coston2.testnet.flarescan.com/address/0x075bf301fF07C4920e5261f93a0609640F53487D) + - Songbird - [Flare + Explorer](https://songbird-explorer.flare.network/address/0xd283afC5A67E2d4Bc700b5B640328Bda22450621) + - + [Flarescan](https://songbird.flarescan.com/address/0xd283afC5A67E2d4Bc700b5B640328Bda22450621) + - Flare - [Flare + Explorer](https://flare-explorer.flare.network/address/0x9394c7A36b3Da8de1b4F27cdD0a554dA4Fa7132d) + - + [Flarescan](https://flare.flarescan.com/address/0x9394c7A36b3Da8de1b4F27cdD0a554dA4Fa7132d) +
diff --git a/examples/developer-hub-javascript/GaslessApp.tsx b/examples/developer-hub-javascript/GaslessApp.tsx index 23d0680f..57c71417 100644 --- a/examples/developer-hub-javascript/GaslessApp.tsx +++ b/examples/developer-hub-javascript/GaslessApp.tsx @@ -1,6 +1,7 @@ -import { useState } from "react"; +import React, { useState } from "react"; import { ethers, Eip1193Provider } from "ethers"; import USD0Abi from "./USD0.json"; +import Heading from "@theme/Heading"; // Environment variables const USD0_ADDRESS = import.meta.env.VITE_USD0_ADDRESS!; @@ -92,7 +93,7 @@ export default function App() { return (
-

Gasless USD₮0 Demo

+ Gasless USD₮0 Demo + + To Hex Converter + + setData(e.target.value)} + className="input-card-input" + /> + +

+ Encoded string: {encodedData} +

+
+ ); +} diff --git a/src/components/FDC/VotingRoundIdCalculator.tsx b/src/components/FDC/VotingRoundIdCalculator.tsx new file mode 100644 index 00000000..ce367bb1 --- /dev/null +++ b/src/components/FDC/VotingRoundIdCalculator.tsx @@ -0,0 +1,48 @@ +import React, { useState } from "react"; +import "@site/src/css/custom.css"; +import classes from "../HomepageFeatures/featureCard.module.css"; +import Heading from "@theme/Heading"; + +export default function RoundCalculator() { + const [timestamp, setTimestamp] = useState(""); + const [roundId, setRoundId] = useState(""); + + async function calculateRoundId(blockTimestamp) { + const firsVotingRoundStartTs = 1658430000; + const votingEpochDurationSeconds = 90; + return Math.floor( + (blockTimestamp - firsVotingRoundStartTs) / votingEpochDurationSeconds, + ); + } + + async function handleClick() { + const result = await calculateRoundId(parseInt(timestamp)); + setRoundId(result.toString()); + } + + return ( +
+ + Voting Round ID Calculator + + setTimestamp(e.target.value)} + className="input-card-input" + /> + +

+ Round ID: {roundId} +

+
+ ); +} diff --git a/src/css/custom.css b/src/css/custom.css index c4fcd219..e7e9173a 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -128,15 +128,20 @@ h3, } h4 { - font-weight: 575; /* Specific weight for h4 */ + font-weight: 575; + /* Specific weight for h4 */ } + body { - font-weight: 450; /* Specific weight for body */ + font-weight: 450; + /* Specific weight for body */ } [data-theme="dark"] p { - color: #ababab; /* Off-white in dark mode */ + color: #ababab; + /* Off-white in dark mode */ } + html[data-theme="dark"] .markdown ul li, html[data-theme="dark"] .markdown ol li { color: #ababab; @@ -181,6 +186,7 @@ div[class^="announcementBar"] { .navbar { background-color: var(--ifm-navbar-background-color); } + .navbar__title { color: var(--ifm-menu-color-active); font-weight: var(--ifm-card-font-weight); @@ -188,7 +194,8 @@ div[class^="announcementBar"] { } .navbar-sidebar__back { - display: none; /* Hides the "Back" button on mobile sidebar */ + display: none; + /* Hides the "Back" button on mobile sidebar */ } .navbar__items { @@ -199,6 +206,7 @@ div[class^="announcementBar"] { .navbar__toggle { color: #1c1b1f; } + [data-theme="dark"] .navbar__toggle { color: #ffffff; } @@ -214,6 +222,7 @@ div[class^="announcementBar"] { transition: background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default); } + .header-github-link:hover::before { background-color: var(--ifm-navbar-link-hover-color); } @@ -221,6 +230,7 @@ div[class^="announcementBar"] { .github-logo-sidebar { display: none; } + @media (max-width: 996px) { .navbar__title { display: none; @@ -237,9 +247,11 @@ div[class^="announcementBar"] { width: 270px; height: 42px; } + .navbar__search-input:hover { outline: solid var(--ifm-global-border-width) var(--ifm-color-primary); } + .navbar__search-input:focus-visible { outline: solid var(--ifm-global-border-width) var(--ifm-color-primary); } @@ -250,13 +262,16 @@ div[class^="searchBar_"] .dropdown-menu { padding: 0px; background-color: var(--ifm-navbar-search-dropdown-bg); border-radius: var(--ifm-global-radius); - border: 1px solid var(--ifm-toc-border-color); /* Use an existing border color variable */ + border: 1px solid var(--ifm-toc-border-color); + /* Use an existing border color variable */ } + div[class^="searchBar_"] .dropdown-menu a[class^="suggestion_"] { /* Target suggestion links */ margin: 1px; border-radius: 0px; } + div[class^="searchBar_"] div[class*="hitFooter"] { /* Target footer, use class contains */ margin-top: 1px; @@ -267,14 +282,18 @@ div[class^="searchBar_"] div[class*="hitFooter"] { height: 56px; font-size: 16px; font-weight: 500; - line-height: 1.35; /* Use relative line height. Removed !important */ + line-height: 1.35; + /* Use relative line height. Removed !important */ background-color: var(--ifm-navbar-search-dropdown-bg); - border-top: 1px solid var(--ifm-toc-border-color); /* Add separator */ + border-top: 1px solid var(--ifm-toc-border-color); + /* Add separator */ } + div[class^="searchBar_"] div[class*="hitFooter"] a { text-decoration: none; color: var(--ifm-color-primary); } + div[class^="searchBar_"] div[class*="hitFooter"] a:hover { text-decoration: underline; } @@ -292,9 +311,11 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { padding-left: 0.75rem; padding-right: 0.75rem; } + .menu__list-item { font-size: 15px; } + .menu__list-item:not(:first-child) { margin-top: 0.75rem; } @@ -303,9 +324,11 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { .menu__link { padding: 10px 12px; } + .menu__link--active { border-left: 4px solid var(--ifm-color-primary-darkest); } + [data-theme="dark"] .menu__link--active { border-left: 4px solid var(--ifm-color-primary-lighter); } @@ -313,6 +336,7 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { .menu__list-item-collapsible--active { background-color: var(--ifm-menu-color-background-active); } + [data-theme="dark"] .menu__list-item-collapsible--active { background-color: var(--ifm-menu-color-background-active); } @@ -335,10 +359,12 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { .menu__link[href*="/fassets/overview"]::before { content: " "; display: block; - flex-shrink: 0; /* Prevent icon shrinking */ + flex-shrink: 0; + /* Prevent icon shrinking */ background-repeat: no-repeat; background-position: center; - margin-right: 10px; /* Consistent margin */ + margin-right: 10px; + /* Consistent margin */ /* Specific sizes set below */ } @@ -349,6 +375,7 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { background-size: 28px auto; background-image: url("/img/menu/FTSO_light.svg"); } + [data-theme="dark"] .menu__link[href*="/ftso/overview"]::before { background-image: url("/img/menu/FTSO_dark.svg"); } @@ -359,6 +386,7 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { background-size: 26px 26px; background-image: url("/img/menu/DATACONNECTOR_light.svg"); } + [data-theme="dark"] .menu__link[href*="/fdc/overview"]::before { background-image: url("/img/menu/DATACONNECTOR_dark.svg"); } @@ -369,6 +397,7 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { background-size: 26px 26px; background-image: url("/img/menu/FASSETS_light.svg"); } + [data-theme="dark"] .menu__link[href*="/fassets/overview"]::before { background-image: url("/img/menu/FASSETS_dark.svg"); } @@ -378,10 +407,12 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { padding: 4px 12px; width: fit-content; } + .table-of-contents__link--active { color: var(--ifm-menu-color-active); background-color: var(--ifm-menu-color-background-active); } + [data-theme="dark"] .table-of-contents__link--active { color: var(--ifm-menu-color-active); background-color: var(--ifm-menu-color-background-active); @@ -391,18 +422,22 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { .breadcrumbs__item { text-transform: uppercase; } + .breadcrumbs__item a { border: 1px solid var(--ifm-navbar-link-color); text-transform: uppercase; } + .breadcrumbs__item a:hover { border-color: var(--ifm-color-primary); } + .breadcrumbs__item a svg { stroke: var(--ifm-color-content); stroke-width: 1.5; color: transparent; } + .breadcrumbs__item:not(:last-child):after { opacity: 1; } @@ -411,34 +446,42 @@ div[class^="searchBar_"] div[class*="hitFooter"] a:hover { table tr:nth-child(2n) { background-color: transparent; } + table tr:nth-child(n) { background-color: transparent; } + table th:first-child, td:first-child { border-left: none; } + table th:last-child, td:last-child { background-color: transparent; border-right: none; } + table tr:first-child th, tr:first-child td { border-top: none; } + table thead { background-color: transparent; } + table thead tr { border-top: none; border-bottom: none; } + table tr:last-child th, tr:last-child td { border-bottom: none; background-color: transparent; } + /* End Basic Table Reset */ /** Data table for FTSO feeds with copy button */ @@ -446,7 +489,8 @@ tr:last-child td { .data-table { /* width: 100%; /* Already set by basic reset */ /* border-collapse: collapse; /* Already set */ - table-layout: auto; /* Allow table to size based on content */ + table-layout: auto; + /* Allow table to size based on content */ } .data-table .table-header th { @@ -457,20 +501,25 @@ tr:last-child td { font-size: 16px; border-bottom-width: 1px; } + [data-theme="light"] .data-table .table-header th { border-bottom-color: rgba(0, 0, 0, 0.2); } + [data-theme="dark"] .data-table .table-header th { border-bottom-color: rgba(255, 255, 255, 0.2); } .data-table .table-row td { padding: 12px; - vertical-align: middle; /* Align content vertically */ + vertical-align: middle; + /* Align content vertically */ } + [data-theme="light"] .data-table .table-row td { border-bottom-color: rgba(0, 0, 0, 0.1); } + [data-theme="dark"] .data-table .table-row td { border-bottom-color: rgba(255, 255, 255, 0.1); } @@ -494,12 +543,14 @@ tr:last-child td { border-radius: var(--ifm-global-radius); display: inline-block; } + [data-theme="light"] .data-table .feed-id-text, [data-theme="light"] .data-table .feed-index-text { background-color: #f6f7f8; border-color: rgba(0, 0, 0, 0.1); color: #1c1e21; } + [data-theme="dark"] .data-table .feed-id-text, [data-theme="dark"] .data-table .feed-index-text { background-color: rgba(255, 255, 255, 0.1); @@ -511,12 +562,16 @@ tr:last-child td { align-items: center; gap: 4px; } + .data-table .feed-id-text { - flex-grow: 1; /* Allow text to take available space */ + flex-grow: 1; + /* Allow text to take available space */ } + .data-table .pointer { cursor: pointer; } + @media (max-width: 768px) { .data-table .feed-id-container { gap: 4px; @@ -535,10 +590,12 @@ tr:last-child td { border-radius: var(--ifm-global-radius); box-shadow: var(--ifm-global-shadow-lw); } + .tippy-box[data-theme="custom"] .tippy-arrow { color: #333; border-width: 6px; } + @media screen and (max-width: 768px) { .tippy-box[data-theme="custom"] { font-size: 12px; @@ -587,6 +644,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .opblock-tag { color: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .opblock-tag { color: var(--ifm-swagger-heading-dark); } @@ -622,6 +680,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .parameter__name { color: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .parameter__name { color: var(--ifm-swagger-heading-dark); } @@ -639,6 +698,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .response-col_status { color: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .response-col_status { color: var(--ifm-swagger-heading-dark); } @@ -646,6 +706,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .response-col_links { color: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .response-col_links { color: var(--ifm-swagger-heading-dark); } @@ -663,6 +724,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui svg:not(:root) { fill: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui svg:not(:root) { fill: var(--ifm-swagger-heading-dark); } @@ -670,6 +732,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .authorization__btn .unlocked { fill: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .authorization__btn .unlocked { fill: var(--ifm-swagger-heading-dark); } @@ -698,6 +761,7 @@ tr:last-child td { [data-theme="dark"] .swagger-ui .model-title { color: var(--ifm-swagger-heading-light); } + [data-theme="light"] .swagger-ui .model-title { color: var(--ifm-swagger-heading-dark); } @@ -755,32 +819,39 @@ tr:last-child td { transition-property: border, box-shadow; box-shadow: none; } + .custom-card:hover { border-color: var(--ifm-color-primary); box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.2); text-decoration: none; } + [data-theme="dark"] .custom-card:hover { border-color: var(--ifm-color-primary); box-shadow: 0 3px 6px 0 rgba(255, 255, 255, 0.2); } + .custom-card-content { display: flex; flex-direction: column; z-index: 1; } + .custom-card-title { font-family: var(--ifm-font-family-base); font-weight: var(--ifm-card-font-weight); font-size: 1.25rem; color: var(--ifm-color-primary); margin-bottom: 0.5rem; - margin-right: 1.5rem; /* Space for arrow */ + margin-right: 1.5rem; + /* Space for arrow */ line-height: 1.4; } + [data-theme="dark"] .custom-card-title { color: #ffffff; } + .custom-card-date { font-family: var(--ifm-font-family-base); font-size: 0.9rem; @@ -788,9 +859,11 @@ tr:last-child td { color: #777777; margin-bottom: 0; } + [data-theme="dark"] .custom-card-date { color: #999999; } + .custom-card-description { font-family: var(--ifm-font-family-base); font-size: 0.9rem; @@ -810,6 +883,7 @@ tr:last-child td { transform 0.2s ease-in-out, color 0.2s ease-in-out; } + [data-theme="dark"] .custom-card-arrow { color: #ffffff; } @@ -818,14 +892,17 @@ tr:last-child td { .developer-tools-container { margin: 2rem 0; } + .developer-tools-header { margin-bottom: 2.5rem; } + .developer-tools-header h1 { font-weight: 500; font-size: 2.5rem; margin-bottom: 1rem; } + .developer-tools-header p { font-size: 1.1rem; line-height: 1.6; @@ -844,9 +921,11 @@ tr:last-child td { display: flex; align-items: center; } + [data-theme="light"] .network-selector-container { background-color: #f5f5f5; } + .network-selector { display: flex; align-items: center; @@ -854,6 +933,7 @@ tr:last-child td { position: relative; width: 100%; } + .network-select { flex: 1; padding: 0.75rem 1rem; @@ -872,9 +952,11 @@ tr:last-child td { background-size: 1em; padding-right: 2.5rem; } + [data-theme="dark"] .network-select { background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); } + .network-select:focus { outline: none; border-color: var(--ifm-color-primary); @@ -907,9 +989,11 @@ tr:last-child td { .developer-tools-container { margin: 2rem 0; } + .developer-tools-header { margin-bottom: 2.5rem; } + .developer-tools-header p { font-size: 1.1rem; line-height: 1.6; @@ -922,6 +1006,7 @@ tr:last-child td { .category-section { margin-bottom: 2.5rem; } + .category-title { font-size: 1.5rem; font-weight: 500; @@ -931,6 +1016,7 @@ tr:last-child td { position: relative; color: var(--ifm-heading-color); } + /* Anchor Link Styling for Category Titles */ .category-title .header-anchor { color: inherit; @@ -938,15 +1024,18 @@ tr:last-child td { display: inline-flex; align-items: center; } + .category-title .header-anchor::before { content: "#"; opacity: 0; margin-right: 0.5rem; transition: opacity 0.2s; font-size: 0.9em; - font-weight: bold; /* Make anchor more visible */ + font-weight: bold; + /* Make anchor more visible */ color: var(--ifm-color-primary); } + .category-title:hover .header-anchor::before { opacity: 1; } @@ -956,6 +1045,7 @@ tr:last-child td { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.5rem; } + .empty-category { grid-column: 1 / -1; padding: 2rem; @@ -965,6 +1055,7 @@ tr:last-child td { color: var(--ifm-font-color-disabled); font-style: italic; } + [data-theme="light"] .empty-category { background-color: rgba(0, 0, 0, 0.03); } @@ -974,11 +1065,13 @@ tr:last-child td { .tools-cards { grid-template-columns: 1fr; } + .network-selector { flex-direction: column; align-items: flex-start; gap: 0.5rem; } + .network-select { width: 100%; } @@ -993,8 +1086,10 @@ tr:last-child td { /* padding-bottom: 56.25%; /* 9 / 16 * 100 */ /* Or use the modern aspect-ratio property */ aspect-ratio: 16 / 9; - margin: 30px auto; /* Example margin, adjust as needed */ - max-width: 784px; /* Optional: Limit max width */ + margin: 30px auto; + /* Example margin, adjust as needed */ + max-width: 784px; + /* Optional: Limit max width */ } .youtube-embed-iframe { @@ -1003,5 +1098,62 @@ tr:last-child td { left: 0; width: 100%; height: 100%; - border: 0; /* Remove default border */ + border: 0; + /* Remove default border */ +} + +/* Input Card Styles (renamed from Voting Round) */ +.input-card { + width: 100%; + background: var(--ifm-color-primary) !important; + color: #fff; + max-width: unset; + margin: 0; + box-sizing: border-box; +} + +.input-card-title { + margin-bottom: 16px; + color: #fff; +} + +.input-card-input { + padding: 10px 12px; + border-radius: 8px; + border: 1px solid #fff; + margin-bottom: 16px; + width: 100%; + font-size: 16px; + color: var(--ifm-color-primary); + background: #fff; + box-sizing: border-box; +} + +.input-card-button { + border-radius: 8px; + width: 100%; + height: 44px; + background: #fff; + color: var(--ifm-color-primary); + border: none; + font-size: 18px; + font-weight: 600; + margin-bottom: 16px; + cursor: pointer; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: + background 0.2s, + color 0.2s; +} + +.input-card-button:hover { + background: var(--ifm-color-primary-dark); + color: #fff; +} + +.input-card-result { + text-align: center; + font-size: 18px; + margin: 0; + color: #fff; } diff --git a/static/img/fdc-by-hand/da-proof-by-request-round-expanded.png b/static/img/fdc-by-hand/da-proof-by-request-round-expanded.png new file mode 100644 index 00000000..5c8153cf Binary files /dev/null and b/static/img/fdc-by-hand/da-proof-by-request-round-expanded.png differ diff --git a/static/img/fdc-by-hand/da-response.png b/static/img/fdc-by-hand/da-response.png new file mode 100644 index 00000000..2f14dea2 Binary files /dev/null and b/static/img/fdc-by-hand/da-response.png differ diff --git a/static/img/fdc-by-hand/da-try-it-out.png b/static/img/fdc-by-hand/da-try-it-out.png new file mode 100644 index 00000000..8ed172c8 Binary files /dev/null and b/static/img/fdc-by-hand/da-try-it-out.png differ diff --git a/static/img/fdc-by-hand/fdc-hub.png b/static/img/fdc-by-hand/fdc-hub.png new file mode 100644 index 00000000..b2dfb90d Binary files /dev/null and b/static/img/fdc-by-hand/fdc-hub.png differ diff --git a/static/img/fdc-by-hand/fdc-request-fee-configurations.png b/static/img/fdc-by-hand/fdc-request-fee-configurations.png new file mode 100644 index 00000000..4a8ec557 Binary files /dev/null and b/static/img/fdc-by-hand/fdc-request-fee-configurations.png differ diff --git a/static/img/fdc-by-hand/fdc-verification.png b/static/img/fdc-by-hand/fdc-verification.png new file mode 100644 index 00000000..48bf82c7 Binary files /dev/null and b/static/img/fdc-by-hand/fdc-verification.png differ diff --git a/static/img/fdc-by-hand/systems-explorer-advanced-finalizations.png b/static/img/fdc-by-hand/systems-explorer-advanced-finalizations.png new file mode 100644 index 00000000..5b6c6a5f Binary files /dev/null and b/static/img/fdc-by-hand/systems-explorer-advanced-finalizations.png differ diff --git a/static/img/fdc-by-hand/systems-explorer-attestation-requests.png b/static/img/fdc-by-hand/systems-explorer-attestation-requests.png new file mode 100644 index 00000000..f4e34ed3 Binary files /dev/null and b/static/img/fdc-by-hand/systems-explorer-attestation-requests.png differ diff --git a/static/img/fdc-by-hand/systems-explorer-finalizations.png b/static/img/fdc-by-hand/systems-explorer-finalizations.png new file mode 100644 index 00000000..93bc5d2e Binary files /dev/null and b/static/img/fdc-by-hand/systems-explorer-finalizations.png differ diff --git a/static/img/fdc-by-hand/verifier-address-validity-prepare-request-expanded.png b/static/img/fdc-by-hand/verifier-address-validity-prepare-request-expanded.png new file mode 100644 index 00000000..3be7bd3a Binary files /dev/null and b/static/img/fdc-by-hand/verifier-address-validity-prepare-request-expanded.png differ diff --git a/static/img/fdc-by-hand/verifier-authorization.png b/static/img/fdc-by-hand/verifier-authorization.png new file mode 100644 index 00000000..a0ad2373 Binary files /dev/null and b/static/img/fdc-by-hand/verifier-authorization.png differ diff --git a/static/img/fdc-by-hand/verifier-authorize.png b/static/img/fdc-by-hand/verifier-authorize.png new file mode 100644 index 00000000..871b6638 Binary files /dev/null and b/static/img/fdc-by-hand/verifier-authorize.png differ diff --git a/static/img/fdc-by-hand/verifier-authorized.png b/static/img/fdc-by-hand/verifier-authorized.png new file mode 100644 index 00000000..ca8f6bfe Binary files /dev/null and b/static/img/fdc-by-hand/verifier-authorized.png differ diff --git a/static/img/fdc-by-hand/verifier-executed-with-data.png b/static/img/fdc-by-hand/verifier-executed-with-data.png new file mode 100644 index 00000000..8136bb8d Binary files /dev/null and b/static/img/fdc-by-hand/verifier-executed-with-data.png differ diff --git a/static/img/fdc-by-hand/verifier-response.png b/static/img/fdc-by-hand/verifier-response.png new file mode 100644 index 00000000..9f40546b Binary files /dev/null and b/static/img/fdc-by-hand/verifier-response.png differ diff --git a/static/img/fdc-by-hand/verifier-try-it-out.png b/static/img/fdc-by-hand/verifier-try-it-out.png new file mode 100644 index 00000000..d76fc4c5 Binary files /dev/null and b/static/img/fdc-by-hand/verifier-try-it-out.png differ