Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions automations/check_new_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -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] = [
Expand Down Expand Up @@ -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"
Expand Down
48 changes: 28 additions & 20 deletions docs/ftso/guides/build-first-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
```

</TabItem>
<TabItem value="hardhat" label="Hardhat">
Expand Down Expand Up @@ -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:
Expand All @@ -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()"
```

<details>
Expand Down Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion docs/network/0-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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/) |

</TabItem>
<TabItem value="songbird" label="Songbird Canary Network">
<TabItem value="songbird" label="Songbird Canary-Network">

| **DA Layer** | [`https://sgb-data-availability.flare.network/api-doc`](https://sgb-data-availability.flare.network/api-doc) |
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
80 changes: 28 additions & 52 deletions docs/network/guides/secure-random-numbers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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.

<details>
<summary>**Understand the mechanism behind secure random numbers on Flare.**</summary>
<summary>Understand the secure random mechanism.</summary>

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.

Expand All @@ -61,33 +62,21 @@ 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]$.

</details>

## Use secure random onchain

:::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.

:::

Expand All @@ -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:

<img src={SetEvmVersionRemix} style={{ width: 300 }} />
- **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 <args>
```
- **Using Standard Solidity JSON:** Set `"evmVersion": "shaghai"` in `settings`.
- **Using `solc`:** Add `--evm-version shanghai` flag to your command.

:::

Expand Down Expand Up @@ -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.

:::

Expand Down Expand Up @@ -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
```

<CodeBlock language="rust" title="secure_random.rs">
{SecureRandomRust}
</CodeBlock>

</TabItem>
<TabItem value="goethereum" label="go-ethereum">
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
Expand Down Expand Up @@ -270,4 +246,4 @@ All examples in this guide are available at [developer-hub/examples](https://git

## Watch the video

<YoutubeEmbed videoId="fdfeWwtd56I?si=QAip5nyQ_urYHmZm"></YoutubeEmbed>
<YoutubeEmbed videoId="fdfeWwtd56I?"></YoutubeEmbed>
8 changes: 4 additions & 4 deletions examples/developer-hub-solidity/SecureRandomConsumer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}