Skip to content

Commit 462a50a

Browse files
authored
fix(docs): ftso first app and secure random (#858)
2 parents 77d4c78 + 7f659df commit 462a50a

File tree

5 files changed

+97
-87
lines changed

5 files changed

+97
-87
lines changed

automations/check_new_feed.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,8 @@ def get(cls, name: str) -> "NetworkConfig":
2929
ISSUES_FILE: Final[Path] = Path("issues.md")
3030
MAX_MARKET_CAP_RANK: Final[int] = 100
3131
MIN_USD_VOLUME: Final[int] = 100_000_000
32+
HEADER_CHAR_LIMIT: Final[int] = 140
3233
GITHUB_NEUTRAL_EXIT: Final[int] = 78
33-
HEADER_TEMPLATE: Final[str] = """---
34-
title: "[auto_req]: Potential New Feeds"
35-
assignees:
36-
- dineshpinto
37-
labels:
38-
- enhancement
39-
---
40-
"""
4134
_VOLUME_RE = re.compile(r"^\$?\s*([\d,]+(?:\.\d{1,2})?)$")
4235
REGISTRY_ADDRESS: Final[str] = "0xaD67FE66660Fb8dFE9d6b1b4240d8650e30F6019"
4336
NETWORKS: list[NetworkConfig] = [
@@ -145,12 +138,45 @@ def parse_volume(vol_str: str) -> int:
145138
return int(float(num))
146139

147140

141+
def _build_header(coins: list[dict[str, Any]]) -> str:
142+
"""
143+
Build the YAML front-matter with a title that lists coin names.
144+
"""
145+
base = "[auto_req]: Potential New Feeds - "
146+
symbols_all = [c.get("symbol", "N/A") for c in coins]
147+
148+
# Accumulate names until a ~140-char title budget is hit; then append "+N more".
149+
acc: list[str] = []
150+
for symbol in symbols_all:
151+
candidate = ", ".join([*acc, symbol])
152+
if len(base + candidate) <= HEADER_CHAR_LIMIT:
153+
acc.append(symbol)
154+
else:
155+
break
156+
if len(acc) < len(symbols_all):
157+
title_symbols = f"{', '.join(acc)} (+{len(symbols_all) - len(acc)} more)"
158+
else:
159+
title_symbols = ", ".join(acc)
160+
161+
safe_title_symbols = title_symbols.replace('"', r"\"")
162+
163+
return (
164+
f"---\n"
165+
f'title: "{base}{safe_title_symbols}"\n'
166+
f"assignees:\n"
167+
f" - dineshpinto\n"
168+
f"labels:\n"
169+
f" - enhancement\n"
170+
f"---\n"
171+
)
172+
173+
148174
def write_issue(coins: list[dict[str, Any]]) -> None:
149175
lines = [
150-
"Coins matching [FIP.08](https://proposals.flare.network/FIP/FIP_8.html) criteria:\n"
176+
"Feeds potentially matching [FIP.08](https://proposals.flare.network/FIP/FIP_8.html) criteria:\n"
151177
]
152178
lines += [f"## {c.get('name', 'N/A')}\n{prettify_coin(c)}\n" for c in coins]
153-
content = HEADER_TEMPLATE + "\n".join(lines)
179+
content = _build_header(coins) + "\n".join(lines)
154180
tmp = ISSUES_FILE.with_suffix(".tmp")
155181
tmp.write_text(
156182
content if content.endswith("\n") else content + "\n", encoding="utf-8"

docs/ftso/guides/build-first-app.mdx

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -224,27 +224,27 @@ This guide is for developers who want to build an FTSOv2 application using eithe
224224
forge test
225225
```
226226

227-
You should see a successful test result like this:
227+
You should see a successful test result:
228228

229-
```plaintext
230-
[⠊] Compiling...
231-
[⠘] Compiling 27 files with Solc 0.8.27
232-
[⠃] Solc 0.8.27 finished in 797.51ms
233-
Compiler run successful!
229+
```plaintext
230+
[⠊] Compiling...
231+
[⠘] Compiling 27 files with Solc 0.8.27
232+
[⠃] Solc 0.8.27 finished in 797.51ms
233+
Compiler run successful!
234234
235-
Ran 2 tests for test/FtsoV2FeedConsumer_foundry.t.sol:FtsoV2FeedConsumerTestFoundry
236-
[PASS] testCheckFees() (gas: 21085)
237-
[PASS] testGetFlrUsdPrice() (gas: 25610)
238-
Logs:
239-
msg.value matches fee
240-
feedValue 150000
241-
decimals 7
242-
timestamp 1
235+
Ran 2 tests for test/FtsoV2FeedConsumer_foundry.t.sol:FtsoV2FeedConsumerTestFoundry
236+
[PASS] testCheckFees() (gas: 21085)
237+
[PASS] testGetFlrUsdPrice() (gas: 25610)
238+
Logs:
239+
msg.value matches fee
240+
feedValue 150000
241+
decimals 7
242+
timestamp 1
243243
244-
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.72ms (2.91ms CPU time)
244+
Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.72ms (2.91ms CPU time)
245245
246-
Ran 1 test suite in 122.65ms (7.72ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
247-
```
246+
Ran 1 test suite in 122.65ms (7.72ms CPU time): 2 tests passed, 0 failed, 0 skipped (2 total tests)
247+
```
248248

249249
</TabItem>
250250
<TabItem value="hardhat" label="Hardhat">
@@ -308,15 +308,20 @@ This guide is for developers who want to build an FTSOv2 application using eithe
308308
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:
309309

310310
```bash
311+
# see https://dev.flare.network/ftso/solidity-reference
311312
export FTSOV2_COSTON2=0x3d893C53D9e8056135C26C8c638B76C8b60Df726
312313
export FEECALCULATOR_COSTON2=0x88A9315f96c9b5518BBeC58dC6a914e13fAb13e2
314+
# see https://dev.flare.network/ftso/feeds
313315
export FLRUSD_FEED_ID=0x01464c522f55534400000000000000000000000000
314316
```
315317

316318
You can now deploy the contract:
317319

318320
```bash
319-
forge create src/FtsoV2FeedConsumer.sol:FtsoV2FeedConsumer --private-key $ACCOUNT_PRIVATE_KEY --rpc-url $RPC_URL --constructor-args $FTSOV2_COSTON2 $FEECALCULATOR_COSTON2 $FLRUSD_FEED_ID
321+
forge create src/FtsoV2FeedConsumer.sol:FtsoV2FeedConsumer \
322+
--private-key $ACCOUNT_PRIVATE_KEY \
323+
--rpc-url $RPC_URL \
324+
--constructor-args $FTSOV2_COSTON2 $FEECALCULATOR_COSTON2 $FLRUSD_FEED_ID
320325
```
321326

322327
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
338343
5. Use `cast` to interact with the contract, note that this command uses the environment variables defined in the sections above.:
339344

340345
```bash
341-
cast send --private-key $ACCOUNT_PRIVATE_KEY --rpc-url $RPC_URL -j --value 0 $DEPLOYMENT_ADDRESS "getFlrUsdPrice()"
346+
cast send \
347+
--private-key $ACCOUNT_PRIVATE_KEY \
348+
--rpc-url $RPC_URL -j \
349+
--value 0 $DEPLOYMENT_ADDRESS "getFlrUsdPrice()"
342350
```
343351

344352
<details>
@@ -479,7 +487,7 @@ This guide is for developers who want to build an FTSOv2 application using eithe
479487

480488
3. Interact with the contract:
481489

482-
Copy and paste the deployed contract address into the [Coston2 explorer](https://coston2-explorer.flare.network/) to view and interact with the contract.
490+
Copy and paste the deployed contract address into the [Coston2 explorer](https://coston2.testnet.flarescan.com) to view and interact with the contract.
483491

484492
Congratulations! You've built your first FTSOv2 app using Hardhat.
485493

docs/network/0-overview.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ Resources for interacting with Flare's DA Layer and FDC verifiers.
293293
| **FDC Verifier (Web2Json)** | [`https://jq-verifier-test.flare.rocks/`](https://jq-verifier-test.flare.rocks/) |
294294

295295
</TabItem>
296-
<TabItem value="songbird" label="Songbird Canary Network">
296+
<TabItem value="songbird" label="Songbird Canary-Network">
297297

298298
| **DA Layer** | [`https://sgb-data-availability.flare.network/api-doc`](https://sgb-data-availability.flare.network/api-doc) |
299299
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |

docs/network/guides/secure-random-numbers.mdx

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import Tabs from "@theme/Tabs";
2424
import Remix from "@site/src/components/remix";
2525
import CodeBlock from "@theme/CodeBlock";
2626
import SecureRandomConsumer from "!!raw-loader!/examples/developer-hub-solidity/SecureRandomConsumer.sol";
27-
import SetEvmVersionRemix from "/static/img/set-evm-version-remix.png";
2827
import SecureRandomWeb3Js from "!!raw-loader!/examples/developer-hub-javascript/secure_random_coston2_web3.js";
2928
import SecureRandomEthersJs from "!!raw-loader!/examples/developer-hub-javascript/secure_random_coston2_ethers.js";
3029
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
3332
import RandomNumberV2Lottery from "!!raw-loader!/examples/developer-hub-solidity/RandomNumberV2Lottery.sol";
3433
import YoutubeEmbed from "@site/src/components/youtube";
3534

36-
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.
35+
This guide shows how to obtain secure, uniform random numbers on Flare.
36+
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.
37+
The protocol aggregates these values into a final, uniformly distributed random number.
3738

38-
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.
39-
The protocol has an in-built security mechanism to detect manipulation attempts, and will warn the end user if such an attempt is detected.
39+
As long as **any one provider** generates an honest, hidden $n$-bit random value, the sum modulo $2^n$ remains uniform.
40+
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.
4041

4142
<details>
42-
<summary>**Understand the mechanism behind secure random numbers on Flare.**</summary>
43+
<summary>Understand the secure random mechanism.</summary>
4344

4445
As described in the [FTSOv2 whitepaper](/pdf/whitepapers/20240223-FlareTimeSeriesOracleV2.pdf), the Scaling protocol consists of the following phases:
4546

4647
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:
4748

4849
`Hash(address, voting_epoch_id, random_number, price_data)`
49-
- **Random Number**: This commit includes a locally generated random number.
50-
- **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.
50+
- **Random Number**: This Commit includes a locally generated random number.
51+
- **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.
5152

5253
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.
5354

@@ -61,33 +62,21 @@ As described in the [FTSOv2 whitepaper](/pdf/whitepapers/20240223-FlareTimeSerie
6162

6263
**Secure Random Numbers**
6364

64-
For each voting epoch (90 seconds), an overall random number is generated from the local random numbers:
65+
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:
6566

6667
$$
67-
R = \sum_{i} r_i \pmod{N}
68+
R = \left( \sum_{i} r_i \right) \mod{2^n}
6869
$$
6970

70-
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.
71-
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.
72-
73-
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.
74-
75-
**Security Mechanism**
76-
77-
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:
78-
79-
- **True**: If there are no omissions of reveals for the commits provided by the data providers.
80-
- **False**: If any omission exists, or if a reveal does not match the committed value.
81-
82-
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.
71+
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]$.
8372

8473
</details>
8574

8675
## Use secure random onchain
8776

8877
:::tip
8978

90-
You can integrate secure random numbers into your application on Flare for no cost (not even gas!).
79+
You can integrate secure random numbers into your application on Flare for no cost.
9180

9281
:::
9382

@@ -101,36 +90,21 @@ You can integrate secure random numbers into your application on Flare for no co
10190

10291
In addition to the `randomNumber` itself, two other variables are retrieved:
10392

104-
- `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`.
93+
- `isSecure`: A boolean flag indicating whether the random number was generated securely:
94+
- **True**: All providers that committed also revealed, and every reveal matched its commit.
95+
- **False**: at least one omission or mismatch occurred for the round.
96+
Offending providers are penalized and excluded for a number of future rounds; the voting round's randomness is flagged as unsafe.
10597

106-
- `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.
98+
- `timestamp`: The UNIX timestamp marking the end of the voting round during which data was collected from data providers to generate the specific number.
99+
Each voting round lasts for a fixed 90-second window.
107100

108101
:::warning[Set EVM Version to Shanghai]
109102

110-
- **Using Remix:** Set EVM version to `shanghai` in the **Advanced Configurations** section of the **Solidity Compiler** tab:
111-
112-
<img src={SetEvmVersionRemix} style={{ width: 300 }} />
103+
- **Using Remix:** Set EVM version to `shanghai` under **Solidity Compiler****Advanced Configurations**.
113104

114105
- **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).
115-
116-
- **Using Standard Solidity JSON:** Set `evmVersion` to `shanghai`:
117-
118-
```json
119-
{
120-
"settings": {
121-
"optimizer": {
122-
/* ... */
123-
},
124-
"evmVersion": "shanghai"
125-
}
126-
}
127-
```
128-
129-
- **Using `solc` CLI:** Set `--evm-version` to `shanghai`:
130-
131-
```bash
132-
solc --evm-version shanghai <args>
133-
```
106+
- **Using Standard Solidity JSON:** Set `"evmVersion": "shaghai"` in `settings`.
107+
- **Using `solc`:** Add `--evm-version shanghai` flag to your command.
134108

135109
:::
136110

@@ -164,9 +138,10 @@ To obtain a secure random number offchain, you need two key pieces of informatio
164138
- [Rust](/network/guides/flare-for-rust-developers#make-query)
165139
- [Go](/network/guides/flare-for-go-developers#make-query)
166140

167-
:::tip
141+
:::tip[Polling interval]
168142

169-
All examples in this guide are available at [developer-hub/examples](https://github.com/flare-foundation/developer-hub/tree/main/examples).
143+
The value updates every 90s (voting round).
144+
Poll no more than once per round or subscribe to the contract's update in your client.
170145

171146
:::
172147

@@ -228,15 +203,16 @@ All examples in this guide are available at [developer-hub/examples](https://git
228203
This example uses [alloy-rs](https://github.com/alloy-rs) to retrieve a secure random number on Flare Testnet Coston2.
229204

230205
```bash
231-
cargo add alloy eyre tokio --features alloy/full,tokio/rt,tokio/rt-multi-thread,tokio/macros
206+
cargo add alloy eyre tokio
232207
```
208+
233209
<CodeBlock language="rust" title="secure_random.rs">
234210
{SecureRandomRust}
235211
</CodeBlock>
236212

237213
</TabItem>
238214
<TabItem value="goethereum" label="go-ethereum">
239-
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.
215+
This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve a secure random number on Flare Testnet Coston2.
240216

241217
```bash
242218
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
270246

271247
## Watch the video
272248

273-
<YoutubeEmbed videoId="fdfeWwtd56I?si=QAip5nyQ_urYHmZm"></YoutubeEmbed>
249+
<YoutubeEmbed videoId="fdfeWwtd56I?"></YoutubeEmbed>

examples/developer-hub-solidity/SecureRandomConsumer.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ contract SecureRandomConsumer {
2626
function getSecureRandomNumber()
2727
external
2828
view
29-
returns (uint256 randomNumber, bool isSecure, uint256 timestamp)
29+
returns (uint256 randomNumber)
3030
{
3131
(randomNumber, isSecure, timestamp) = randomV2.getRandomNumber();
32-
/* DO NOT USE THE RANDOM NUMBER IF isSecure=false. */
32+
/* DO NOT USE if isSecure=false. Wait till the next voting round (90s). */
3333
require(isSecure, "Random number is not secure");
34-
/* Your custom RNG consumption logic. In this example the values are just returned. */
35-
return (randomNumber, isSecure, timestamp);
34+
/* Your custom RNG consumption logic. Here the random value is just returned. */
35+
return randomNumber;
3636
}
3737
}

0 commit comments

Comments
 (0)