# Fraxtal Merkle 证明预言机

Fraxtal Merkle 预言机（Fraxtal-MOs）是一类预言机，利用 `eth_getProof` RPC 方法在以太坊 L2（如 Fraxtal）上证明 L1 状态。

### 概览

Fraxtal-MOs 利用四个关键合约来验证和传输状态。

[**FraxchainL1Block**](https://fraxscan.com/address/0x4200000000000000000000000000000000000015#code)

预部署合约，用作 L2 上 L1 区块哈希的注册表。

[**StateRootOracle**](https://fraxscan.com/address/0xeD403d48e2bC946438B5686AA1AD65056Ccf9512)

合约用于验证给定的区块头与通过 FraxchainL1Block 合约中继的 L1 区块哈希。该合约负责存储状态根哈希以及 L1 时间戳。

[**MerkleProofPriceSource**](https://fraxscan.com/address/0xe25d8aaa6df41b94a415ee39ccee0df6673b9bdb#code)

合约执行状态根验证。根据通过 eth\_getProof RPC 方法离线构建的默克尔证明，该合约将验证并提取“证明”的存储槽值到 L2 区块链。这些“证明”的值随后被传递给预言机本身。

传递这些“证明”值的过程是无信任的，任何人都可以提交与给定以太坊 L1 地址的预先批准的槽对应的有效默克尔证明。

[**FraxtalERC4626TransportOracle**](https://fraxscan.com/address/0x1b680f4385f24420d264d78cab7c58365ed3f1ff#readContract)

合约接受来自 MerkleProofPriceSoure 合约的“证明” L1 数据。

对于 sFrax 和其他 ERC4626 保险库，这些“证明”的值定义了 L1 上保险库代币价值累积函数的当前斜率。

这些预言机公开以下函数，以允许用户查询相关资产的价格：

```solidity
    /// @dev Adheres to chainlink's AggregatorV3Interface `latestRoundData()`
    /// @return _roundId The l1Block corresponding to the last time the oracle was proofed
    /// @return _answer The price of Sfrax in frax
    /// @return _startedAt The L1 timestamp corresponding to most recent proof
    /// @return _updatedAt Equivalent to `_startedAt`
    /// @return _answeredInRound Equivalent to `_roundId`
    function latestRoundData()
        external
        view
    returns (
        uint80 _roundId, 
        int256 _answer, 
        uint256 _startedAt, 
        uint256 _updatedAt, 
        uint80 _answeredInRound
    )

```

```solidity
/// @return _pricePerShare The current exchange rate of the vault token 
///                        denominated in the underlying vault asset
function pricePerShare() public view 
```

#### 架构

将 L1 数据传输/证明到 L2 的过程：

步骤 1: 在 L2 上证明 L1 的区块头。

![Screenshot 2024-09-23 at 11.04.48 AM](https://hackmd.io/_uploads/HkR4EZyAR.png)

步骤 2: 提交预定义 L1 地址和存储槽的存储证明。

![Screenshot 2024-09-23 at 11.05.00 AM](https://hackmd.io/_uploads/H1ih4-J0C.png)

#### 演示客户端

以下代码应作为生成上述 Fraxtal 智能合约接受的函数参数的示例。\
有关 RPC 方法的文档：`eth_getBlockByNumber` 和 `eth_getProof`生成 L1 区块头的代码。

#### 生成 L1 区块头的代码

```typescript
async function getHeaderFromBlock(provider, blockL1) {
    let block = await provider.send("eth_getBlockByNumber", [blockL1, false])
    let headerFields = [];
    headerFields.push(block.parentHash);
    headerFields.push(block.sha3Uncles);
    headerFields.push(block.miner);
    headerFields.push(block.stateRoot);
    headerFields.push(block.transactionsRoot);
    headerFields.push(block.receiptsRoot);
    headerFields.push(block.logsBloom);
    headerFields.push(block.difficulty);
    headerFields.push(block.number);
    headerFields.push(block.gasLimit);
    headerFields.push(block.gasUsed);
    headerFields.push(block.timestamp);
    headerFields.push(block.extraData);
    headerFields.push(block.mixHash);
    headerFields.push(block.nonce);
    headerFields.push(block.baseFeePerGas);
    if (block.withdrawalsRoot) {
        headerFields.push(block.withdrawalsRoot);
    }
    if (block.blobGasUsed) {
        headerFields.push(block.blobGasUsed);
    }
    if (block.excessBlobGas) {
        headerFields.push(block.excessBlobGas);
    }
    if (block.parentBeaconBlockRoot) {
        headerFields.push(block.parentBeaconBlockRoot);
    }
    convertHeaderFields(headerFields);
    let header = ethers.utils.RLP.encode(headerFields);
    return header
}
```

#### 生成存储证明的代码

```typescript
        let blockToProof = "0x"+blockL1.toHexString().substring(2).replace(/^0+/, "");

        let sfrax_proof = await mainnetProvider.send("eth_getProof", 
        [
            // L1 address to generate proofs for
            SFRAX_MAINNET,
            // Slots to proof 
            [
                "0x0000000000000000000000000000000000000000000000000000000000000002",
                "0x0000000000000000000000000000000000000000000000000000000000000009",
                "0x0000000000000000000000000000000000000000000000000000000000000008",
                "0x0000000000000000000000000000000000000000000000000000000000000006",
                "0x0000000000000000000000000000000000000000000000000000000000000007"
            ], 
            blockToProof
        ]);
    
        // Format the proof info returned from `eth_getProof`
        let proof: Proof = {} as Proof;
        proof._accountProofSfrax = sfrax_proof.accountProof;
        proof._storageProofTotalSupply = sfrax_proof.storageProof[0].proof;
        proof._storageProofTotalAssets = sfrax_proof.storageProof[1].proof;
        proof._storageProofLastDist = sfrax_proof.storageProof[2].proof;
        proof._storageProofRewardsPacked = sfrax_proof.storageProof[3].proof;
        proof._storageProofRewardsCycleAmount = sfrax_proof.storageProof[4].proof;

        let txn = await proover.addRoundDataSfrax(
            SFRAX_L2_ORACLE,
            blockL1.toString(),
            proof
        )
```

#### 已部署的合约

| Description    | Oracle                                                                                                                       | MerkleProofPriceSource                                                                                                       |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| sFrax/Frax     | [`0x1b680f4385f24420d264d78cab7c58365ed3f1ff`](https://fraxscan.com/address/0x1b680f4385f24420d264d78cab7c58365ed3f1ff#code) | [`0xe25d8aaa6df41b94a415ee39ccee0df6673b9bdb`](https://fraxscan.com/address/0xe25d8aaa6df41b94a415ee39ccee0df6673b9bdb#code) |
| sfrxEth/frxEth | [`0xEE095b7d9191603126Da584a1179BB403a027c3A`](https://fraxscan.com/address/0xEE095b7d9191603126Da584a1179BB403a027c3A#code) | [`0xabca0b314d15B3e28F24AC0ee84A63001d1b44Db`](https://fraxscan.com/address/0xabca0b314d15B3e28F24AC0ee84A63001d1b44Db#code) |
| FPI/USD        | [`0x0f50beeE2d2506634b1e6230F3867e30763CbB02`](https://fraxscan.com/address/0x0f50beeE2d2506634b1e6230F3867e30763CbB02#code) | [`0x8fc7425Cd36D7e4605650198099e4539238e9c37`](https://fraxscan.com/address/0x8fc7425Cd36D7e4605650198099e4539238e9c37#code) |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.frax.finance/zh/frax-yu-yan-ji/fraxtal-merkle-zheng-ming-yu-yan-ji.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
