Fraxtal Merkle 预言机(Fraxtal-MOs)是一类预言机,利用 eth_getProof
RPC 方法在以太坊 L2(如 Fraxtal)上证明 L1 状态。
概览
Fraxtal-MOs 利用四个关键合约来验证和传输状态。
FraxchainL1Block
预部署合约,用作 L2 上 L1 区块哈希的注册表。
StateRootOracle
合约用于验证给定的区块头与通过 FraxchainL1Block 合约中继的 L1 区块哈希。该合约负责存储状态根哈希以及 L1 时间戳。
MerkleProofPriceSource
合约执行状态根验证。根据通过 eth_getProof RPC 方法离线构建的默克尔证明,该合约将验证并提取“证明”的存储槽值到 L2 区块链。这些“证明”的值随后被传递给预言机本身。
传递这些“证明”值的过程是无信任的,任何人都可以提交与给定以太坊 L1 地址的预先批准的槽对应的有效默克尔证明。
FraxtalERC4626TransportOracle
合约接受来自 MerkleProofPriceSoure 合约的“证明” L1 数据。
对于 sFrax 和其他 ERC4626 保险库,这些“证明”的值定义了 L1 上保险库代币价值累积函数的当前斜率。
这些预言机公开以下函数,以允许用户查询相关资产的价格:
Copy /// @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
)
Copy /// @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 的区块头。
步骤 2: 提交预定义 L1 地址和存储槽的存储证明。
演示客户端
以下代码应作为生成上述 Fraxtal 智能合约接受的函数参数的示例。
有关 RPC 方法的文档:eth_getBlockByNumber
和 eth_getProof
生成 L1 区块头的代码。
生成 L1 区块头的代码
Copy 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
}
生成存储证明的代码
Copy 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
Last updated 4 months ago