diff --git a/automations/check_new_feed.py b/automations/check_new_feed.py
index 75f6e41f..a55cb692 100644
--- a/automations/check_new_feed.py
+++ b/automations/check_new_feed.py
@@ -29,15 +29,8 @@ def get(cls, name: str) -> "NetworkConfig":
ISSUES_FILE: Final[Path] = Path("issues.md")
MAX_MARKET_CAP_RANK: Final[int] = 100
MIN_USD_VOLUME: Final[int] = 100_000_000
+HEADER_CHAR_LIMIT: Final[int] = 140
GITHUB_NEUTRAL_EXIT: Final[int] = 78
-HEADER_TEMPLATE: Final[str] = """---
-title: "[auto_req]: Potential New Feeds"
-assignees:
- - dineshpinto
-labels:
- - enhancement
----
-"""
_VOLUME_RE = re.compile(r"^\$?\s*([\d,]+(?:\.\d{1,2})?)$")
REGISTRY_ADDRESS: Final[str] = "0xaD67FE66660Fb8dFE9d6b1b4240d8650e30F6019"
NETWORKS: list[NetworkConfig] = [
@@ -145,12 +138,45 @@ def parse_volume(vol_str: str) -> int:
return int(float(num))
+def _build_header(coins: list[dict[str, Any]]) -> str:
+ """
+ Build the YAML front-matter with a title that lists coin names.
+ """
+ base = "[auto_req]: Potential New Feeds - "
+ symbols_all = [c.get("symbol", "N/A") for c in coins]
+
+ # Accumulate names until a ~140-char title budget is hit; then append "+N more".
+ acc: list[str] = []
+ for symbol in symbols_all:
+ candidate = ", ".join([*acc, symbol])
+ if len(base + candidate) <= HEADER_CHAR_LIMIT:
+ acc.append(symbol)
+ else:
+ break
+ if len(acc) < len(symbols_all):
+ title_symbols = f"{', '.join(acc)} (+{len(symbols_all) - len(acc)} more)"
+ else:
+ title_symbols = ", ".join(acc)
+
+ safe_title_symbols = title_symbols.replace('"', r"\"")
+
+ return (
+ f"---\n"
+ f'title: "{base}{safe_title_symbols}"\n'
+ f"assignees:\n"
+ f" - dineshpinto\n"
+ f"labels:\n"
+ f" - enhancement\n"
+ f"---\n"
+ )
+
+
def write_issue(coins: list[dict[str, Any]]) -> None:
lines = [
- "Coins matching [FIP.08](https://proposals.flare.network/FIP/FIP_8.html) criteria:\n"
+ "Feeds potentially matching [FIP.08](https://proposals.flare.network/FIP/FIP_8.html) criteria:\n"
]
lines += [f"## {c.get('name', 'N/A')}\n{prettify_coin(c)}\n" for c in coins]
- content = HEADER_TEMPLATE + "\n".join(lines)
+ content = _build_header(coins) + "\n".join(lines)
tmp = ISSUES_FILE.with_suffix(".tmp")
tmp.write_text(
content if content.endswith("\n") else content + "\n", encoding="utf-8"
diff --git a/docs/ftso/guides/build-first-app.mdx b/docs/ftso/guides/build-first-app.mdx
index 9ec6ea48..2a5eeecd 100644
--- a/docs/ftso/guides/build-first-app.mdx
+++ b/docs/ftso/guides/build-first-app.mdx
@@ -224,27 +224,27 @@ This guide is for developers who want to build an FTSOv2 application using eithe
forge test
```
- You should see a successful test result like this:
+ You should see a successful test result:
- ```plaintext
- [⠊] Compiling...
- [⠘] Compiling 27 files with Solc 0.8.27
- [⠃] Solc 0.8.27 finished in 797.51ms
- Compiler run successful!
+ ```plaintext
+ [⠊] Compiling...
+ [⠘] Compiling 27 files with Solc 0.8.27
+ [⠃] Solc 0.8.27 finished in 797.51ms
+ Compiler run successful!
- Ran 2 tests for test/FtsoV2FeedConsumer_foundry.t.sol:FtsoV2FeedConsumerTestFoundry
- [PASS] testCheckFees() (gas: 21085)
- [PASS] testGetFlrUsdPrice() (gas: 25610)
- Logs:
- msg.value matches fee
- feedValue 150000
- decimals 7
- timestamp 1
+ Ran 2 tests for test/FtsoV2FeedConsumer_foundry.t.sol:FtsoV2FeedConsumerTestFoundry
+ [PASS] testCheckFees() (gas: 21085)
+ [PASS] testGetFlrUsdPrice() (gas: 25610)
+ Logs:
+ msg.value matches fee
+ feedValue 150000
+ decimals 7
+ timestamp 1
- Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.72ms (2.91ms CPU time)
+ Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.72ms (2.91ms CPU time)
- Ran 1 test suite in 122.65ms (7.72ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
- ```
+ Ran 1 test suite in 122.65ms (7.72ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
+ ```
@@ -308,15 +308,20 @@ This guide is for developers who want to build an FTSOv2 application using eithe
4. The final step before deploying is to set the constructor arguments with the address of [`FtsoV2`](/ftso/solidity-reference) and [`FeeCalculator`](/ftso/solidity-reference) on Flare Testnet Coston2 and the [feed ID](/ftso/feeds) of FLR/USD:
```bash
+ # see https://dev.flare.network/ftso/solidity-reference
export FTSOV2_COSTON2=0x3d893C53D9e8056135C26C8c638B76C8b60Df726
export FEECALCULATOR_COSTON2=0x88A9315f96c9b5518BBeC58dC6a914e13fAb13e2
+ # see https://dev.flare.network/ftso/feeds
export FLRUSD_FEED_ID=0x01464c522f55534400000000000000000000000000
```
You can now deploy the contract:
```bash
- forge create src/FtsoV2FeedConsumer.sol:FtsoV2FeedConsumer --private-key $ACCOUNT_PRIVATE_KEY --rpc-url $RPC_URL --constructor-args $FTSOV2_COSTON2 $FEECALCULATOR_COSTON2 $FLRUSD_FEED_ID
+ forge create src/FtsoV2FeedConsumer.sol:FtsoV2FeedConsumer \
+ --private-key $ACCOUNT_PRIVATE_KEY \
+ --rpc-url $RPC_URL \
+ --constructor-args $FTSOV2_COSTON2 $FEECALCULATOR_COSTON2 $FLRUSD_FEED_ID
```
If the deployment is successful, the output will display the contract address, save that for later use:
@@ -338,7 +343,10 @@ This guide is for developers who want to build an FTSOv2 application using eithe
5. Use `cast` to interact with the contract, note that this command uses the environment variables defined in the sections above.:
```bash
- cast send --private-key $ACCOUNT_PRIVATE_KEY --rpc-url $RPC_URL -j --value 0 $DEPLOYMENT_ADDRESS "getFlrUsdPrice()"
+ cast send \
+ --private-key $ACCOUNT_PRIVATE_KEY \
+ --rpc-url $RPC_URL -j \
+ --value 0 $DEPLOYMENT_ADDRESS "getFlrUsdPrice()"
```
@@ -479,7 +487,7 @@ This guide is for developers who want to build an FTSOv2 application using eithe
3. Interact with the contract:
- Copy and paste the deployed contract address into the [Coston2 explorer](https://coston2-explorer.flare.network/) to view and interact with the contract.
+ Copy and paste the deployed contract address into the [Coston2 explorer](https://coston2.testnet.flarescan.com) to view and interact with the contract.
Congratulations! You've built your first FTSOv2 app using Hardhat.
diff --git a/docs/network/0-overview.mdx b/docs/network/0-overview.mdx
index d8637cae..565ec70b 100644
--- a/docs/network/0-overview.mdx
+++ b/docs/network/0-overview.mdx
@@ -293,7 +293,7 @@ Resources for interacting with Flare's DA Layer and FDC verifiers.
| **FDC Verifier (Web2Json)** | [`https://jq-verifier-test.flare.rocks/`](https://jq-verifier-test.flare.rocks/) |
-
+
| **DA Layer** | [`https://sgb-data-availability.flare.network/api-doc`](https://sgb-data-availability.flare.network/api-doc) |
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
diff --git a/docs/network/guides/secure-random-numbers.mdx b/docs/network/guides/secure-random-numbers.mdx
index 1251bc9f..7b0402b4 100644
--- a/docs/network/guides/secure-random-numbers.mdx
+++ b/docs/network/guides/secure-random-numbers.mdx
@@ -24,7 +24,6 @@ import Tabs from "@theme/Tabs";
import Remix from "@site/src/components/remix";
import CodeBlock from "@theme/CodeBlock";
import SecureRandomConsumer from "!!raw-loader!/examples/developer-hub-solidity/SecureRandomConsumer.sol";
-import SetEvmVersionRemix from "/static/img/set-evm-version-remix.png";
import SecureRandomWeb3Js from "!!raw-loader!/examples/developer-hub-javascript/secure_random_coston2_web3.js";
import SecureRandomEthersJs from "!!raw-loader!/examples/developer-hub-javascript/secure_random_coston2_ethers.js";
import SecureRandomWeb3Py from "!!raw-loader!/examples/developer-hub-python/secure_random_coston2.py";
@@ -33,21 +32,23 @@ import SecureRandomGo from "!!raw-loader!/examples/developer-hub-go/coston2/secu
import RandomNumberV2Lottery from "!!raw-loader!/examples/developer-hub-solidity/RandomNumberV2Lottery.sol";
import YoutubeEmbed from "@site/src/components/youtube";
-This guide explains how to obtain secure random numbers on Flare. Secure randomness is generated by the [Scaling](/ftso/scaling/overview) protocol, which leverages a decentralized network of approximately 100 data providers who generate random numbers every 90 seconds.
+This guide shows how to obtain secure, uniform random numbers on Flare.
+Secure randomness is generated by the [Scaling](/ftso/scaling/overview) protocol, where approximately 100 independent data providers generate local randomness every 90 seconds (a voting round), commit onchain, then reveal.
+The protocol aggregates these values into a final, uniformly distributed random number.
-The protocol aggregates these individual random numbers to produce a final random number that is both uniform and resistant to manipulation. The uniformity of this random number is ensured as long as at least one of the data providers remains honest, i.e. 1-of-N.
-The protocol has an in-built security mechanism to detect manipulation attempts, and will warn the end user if such an attempt is detected.
+As long as **any one provider** generates an honest, hidden $n$-bit random value, the sum modulo $2^n$ remains uniform.
+If manipulation is detected (e.g., a reveal omission), the round's `isSecure` flag is set to false, offenders are penalized, and their values are excluded for subsequent rounds.
-**Understand the mechanism behind secure random numbers on Flare.**
+Understand the secure random mechanism.
As described in the [FTSOv2 whitepaper](/pdf/whitepapers/20240223-FlareTimeSeriesOracleV2.pdf), the Scaling protocol consists of the following phases:
1. **Commit:** During the Commit phase, data providers prepare their submissions for each of the data feeds and encode them into a 4-byte vector. Then, each data provider publishes on chain a hash commitment obtained as:
`Hash(address, voting_epoch_id, random_number, price_data)`
- - **Random Number**: This commit includes a locally generated random number.
- - **Purpose**: The random number blinds the commit hash of the user from a search attack and is used later (once revealed) to contribute to onchain randomness.
+ - **Random Number**: This Commit includes a locally generated random number.
+ - **Purpose**: The random number blinds the Commit hash of the user from a search attack and is used later (once revealed) to contribute to onchain randomness.
2. **Reveal:** During the Reveal phase, each data provider reveals all inputs to their hash commitment. As such, all locally produced random numbers become available onchain.
@@ -61,25 +62,13 @@ As described in the [FTSOv2 whitepaper](/pdf/whitepapers/20240223-FlareTimeSerie
**Secure Random Numbers**
-For each voting epoch (90 seconds), an overall random number is generated from the local random numbers:
+For each voting round (90 seconds), let each provider's random value be $r_i \in [0, 2^n -1]$. The voting round's random number is:
$$
-R = \sum_{i} r_i \pmod{N}
+R = \left( \sum_{i} r_i \right) \mod{2^n}
$$
-where $r_i$ is the local random number generated by the $i^{th}$ data provider, and $ N = 2^n $ denotes the maximum possible size of the individual $n$-bit random numbers.
-This mechanism ensures that the resultant $R$ is a uniformly generated random number as long as at least any one of the inputs was an honestly generated uniformly random number.
-
-Importantly, the Merkle root published by the data providers contains a Boolean value that tracks whether the generated random number for the current voting epoch is secure.
-
-**Security Mechanism**
-
-The security mechanism behind the random number generator protects the protocol against withholding attacks. An adversary could wait until all submissions are known and then choose whether or not to reveal their own commit data to influence the final result. This security mechanism measures the quality of the random number as follows:
-
-- **True**: If there are no omissions of reveals for the commits provided by the data providers.
-- **False**: If any omission exists, or if a reveal does not match the committed value.
-
-If a data provider causes an omission (or false reveal), they will be penalized, and their random number will not be included in the random number calculation for a number of voting rounds.
+Because commits are fixed before reveals, if any one $r_i$ is uniformly random and not chosen adaptively after seeing others, $R$ is uniformly random over $[0, 2^n -1]$.
@@ -87,7 +76,7 @@ If a data provider causes an omission (or false reveal), they will be penalized,
:::tip
-You can integrate secure random numbers into your application on Flare for no cost (not even gas!).
+You can integrate secure random numbers into your application on Flare for no cost.
:::
@@ -101,36 +90,21 @@ You can integrate secure random numbers into your application on Flare for no co
In addition to the `randomNumber` itself, two other variables are retrieved:
-- `isSecure`: A boolean flag indicating whether the random number was generated securely. If the protocol detects any attempt to manipulate the random number, this flag is set to `false`.
+- `isSecure`: A boolean flag indicating whether the random number was generated securely:
+ - **True**: All providers that committed also revealed, and every reveal matched its commit.
+ - **False**: at least one omission or mismatch occurred for the round.
+ Offending providers are penalized and excluded for a number of future rounds; the voting round's randomness is flagged as unsafe.
-- `timestamp`: The UNIX timestamp marking the end of the voting epoch during which data was collected from data providers to generate the specific number. Each voting epoch lasts for a fixed 90-second window.
+- `timestamp`: The UNIX timestamp marking the end of the voting round during which data was collected from data providers to generate the specific number.
+ Each voting round lasts for a fixed 90-second window.
:::warning[Set EVM Version to Shanghai]
-- **Using Remix:** Set EVM version to `shanghai` in the **Advanced Configurations** section of the **Solidity Compiler** tab:
-
-
+- **Using Remix:** Set EVM version to `shanghai` under **Solidity Compiler** → **Advanced Configurations**.
- **Using Hardhat or Foundry:** Set EVM version to `shanghai` in [hardhat.config.ts](https://github.com/flare-foundation/flare-hardhat-starter/blob/master/hardhat.config.ts#L34) or [foundry.toml](https://github.com/flare-foundation/flare-foundry-starter/blob/master/foundry.toml).
-
-- **Using Standard Solidity JSON:** Set `evmVersion` to `shanghai`:
-
- ```json
- {
- "settings": {
- "optimizer": {
- /* ... */
- },
- "evmVersion": "shanghai"
- }
- }
- ```
-
-- **Using `solc` CLI:** Set `--evm-version` to `shanghai`:
-
- ```bash
- solc --evm-version shanghai
- ```
+- **Using Standard Solidity JSON:** Set `"evmVersion": "shaghai"` in `settings`.
+- **Using `solc`:** Add `--evm-version shanghai` flag to your command.
:::
@@ -164,9 +138,10 @@ To obtain a secure random number offchain, you need two key pieces of informatio
- [Rust](/network/guides/flare-for-rust-developers#make-query)
- [Go](/network/guides/flare-for-go-developers#make-query)
-:::tip
+:::tip[Polling interval]
-All examples in this guide are available at [developer-hub/examples](https://github.com/flare-foundation/developer-hub/tree/main/examples).
+The value updates every 90s (voting round).
+Poll no more than once per round or subscribe to the contract's update in your client.
:::
@@ -228,15 +203,16 @@ All examples in this guide are available at [developer-hub/examples](https://git
This example uses [alloy-rs](https://github.com/alloy-rs) to retrieve a secure random number on Flare Testnet Coston2.
```bash
- cargo add alloy eyre tokio --features alloy/full,tokio/rt,tokio/rt-multi-thread,tokio/macros
+ cargo add alloy eyre tokio
```
+
{SecureRandomRust}
- This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD from Flare Testnet Coston2.
+ This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve a secure random number on Flare Testnet Coston2.
```bash
go get github.com/ethereum/go-ethereum/ethclient
@@ -270,4 +246,4 @@ All examples in this guide are available at [developer-hub/examples](https://git
## Watch the video
-
+
diff --git a/examples/developer-hub-solidity/SecureRandomConsumer.sol b/examples/developer-hub-solidity/SecureRandomConsumer.sol
index 0ee76d11..e2bd8e2b 100644
--- a/examples/developer-hub-solidity/SecureRandomConsumer.sol
+++ b/examples/developer-hub-solidity/SecureRandomConsumer.sol
@@ -26,12 +26,12 @@ contract SecureRandomConsumer {
function getSecureRandomNumber()
external
view
- returns (uint256 randomNumber, bool isSecure, uint256 timestamp)
+ returns (uint256 randomNumber)
{
(randomNumber, isSecure, timestamp) = randomV2.getRandomNumber();
- /* DO NOT USE THE RANDOM NUMBER IF isSecure=false. */
+ /* DO NOT USE if isSecure=false. Wait till the next voting round (90s). */
require(isSecure, "Random number is not secure");
- /* Your custom RNG consumption logic. In this example the values are just returned. */
- return (randomNumber, isSecure, timestamp);
+ /* Your custom RNG consumption logic. Here the random value is just returned. */
+ return randomNumber;
}
}