# Cairo 之旅 X:与 Empiric 预言机域间通信 **Published by:** [Starknet 中文](https://paragraph.com/@starknet-zh/) **Published on:** 2022-11-14 **URL:** https://paragraph.com/@starknet-zh/cairo-x-empiric ## Content 作者:Darlington Nnam 原文:Journey Through Cairo X: Inter-realm Communications With Empiric Oracle 翻译及校对:「StarkNet 中文社区」 欢迎来到系列文章「Cairo 之旅」第十课!在上一课中,我们使用 Protostar 编写了第一个单元测试,今天我们将学习与 Empiric 预言机域间通信。 像往常一样,如果你是中途加入,建议从头开始看我们的文章。 区块链预言机 (Blockchain Oracle) 区块链预言机是个难以理解的概念尤其是那些初次听说的人们,今天就让我们深入了解。 在希腊神话中,预言家是有特殊能力的人,也被称为祭司,他们拥有与神灵或精神境界互动和交流的能力。他们经常被当作神灵的传声筒,作为了解神灵的想法的唯一方式。 当把预言机概念应用于区块链时,我们就得到了区块链预言机,那么能否将其理解为区块链预言机启用跨领域通信呢? 让我们继续深入研究。 区块链是确定性的 区块链被设定为确定性的,区块链被建立成一个独立的系统(想象没有互联网连接的计算机),并就其分类帐中的数据达成共识。 尽管它在某些方面发挥了重要作用,如有助于区块链获得高度的准确性或确定性,从而使其成为无需信任的系统,但它对智能合约的实现提出了很多限制。 大规模采用是我们所期盼的核心目标之一,当我们无法与外界交互时怎么实现这一目标呢?金融智能合约需要市场信息来确定结算,保险智能合约需要物联网 (Internet of Things) 等。 最大的问题是如何在不牺牲区块链确定性的前提下与外界交互?当然不能只依靠一个中心化实体来提供信息,这否定了去中心化的核心原则,因为中心化实体可能遭遇突发停电,或被破坏的情况。 这些正是区块链预言机试图解决的问题,为区块链上的智能合约运行提供去中心化的方式,使其能在不牺牲区块链确定性的前提下与外界有效交互。 阅读 Chainlink 文章深入了解预言机如何工作。 Empiric — 在 StarkNet 上重塑预言机 就像 Chainlink 解决了以太坊预言机难题,Empiric 也在尝试解决 StarkNet 预言机问题。 利用 ZK 技术创建起一个透明公开、可组合、去中心化的架构。 今天我们深入学习预言机,查看其是如何运行的,并利用 Empiric 的喂价功能来构建第一个混合智能合约 (Hybrid Smart Contract)。 准备工作 首先需要用 Protostar 建立本地环境。 项目描述 构建一个利于用户获取 BTC、ETH 和 SOL 代币价格的简易项目。 必要条件 具备编写 StarkNet 合约的基础知识。 项目初始化 Protostar 设置完后,通过以下指令运行新项目: protostar init 完成后,按照要求输入项目名称和库名称成功创建一个新项目。 编写合约 部署 StarkNet 合约中概述了大部分代码和流程,在此只讲解部分代码。 导入 %lang starknet from starkware.cairo.common.cairo_builtins import HashBuiltin 常量 const EMPIRIC_ORACLE_ADDRESS = 0x012fadd18ec1a23a160cc46981400160fbf4a7a5eed156c4669e39807265bcd4; const ETH_KEY = 28556963469423460; const BTC_KEY = 27712517064455012; const SOL_KEY = 32492132765102948; const AGGREGATION_MODE = 120282243752302; // str_to_felt("median") 定义合约中所需的五个常量: EMPIRIC_ORACLE_ADDRESS:指定部署 Empiric 合约地址。 ETH_KEY:eth/usd 小写 utf8 编码字符串。作为一个指针来通知预言机你需要什么交易对。 BTC_KEY:btc/usd 小写 utf8 编码字符串。 SOL_KEY:sol/usd 小写 utf8 编码字符串。 AGGREGATION_MODE:指定聚合过程获取数据。目前仅支持中值聚合模式 (Median Aggregation Mode),因此我们将字符串 median 转换为 felt,并将其作为参数传输给预言机。 合约接口 @contract_interface namespace IEmpiricOracle{ func get_value(key : felt, aggregation_mode : felt) -> ( value : felt, decimals : felt, last_updated_timestamp : felt, num_sources_aggregated : felt ){ } } 用于与外部合约交互的 Cairo 接口。创建一个包含了我们想要交互的 get_value 函数接口 IEmpiricOracle。 该函数接受键(指定期望价格)和聚合模式,可返回值、小数位数、最新时间戳和聚合源数。 获取比特币资产价格 @view func btc_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){ let ( price, decimals, last_updated_timestamp, num_sources_aggregated ) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, BTC_KEY, AGGREGATION_MODE ); return (price,); } 在指定了所有常量以及合约接口后,开始创建第一个视图函数,他能返回比特币的美元价格。 上述可见我们使用指定的接口调用 Empiric 预言机的 get_value 函数,传入三个参数并不是预期的两个参数。这是因为当我们使用接口调用外部合约时,必须将该合约的地址作为第一个参数。 然后从 Empiric 返回资产价格。 获取以太坊资产价格 @view func eth_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){ let ( price, decimals, last_updated_timestamp, num_sources_aggregated ) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, ETH_KEY, AGGREGATION_MODE ); return (price,); } 这一步要求我们用不同的键重复上述比特币步骤。 获取 Solana 资产价格 @view func sol_price{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}() -> (price: felt){ let ( price, decimals, last_updated_timestamp, num_sources_aggregated ) = IEmpiricOracle.get_value( EMPIRIC_ORACLE_ADDRESS, SOL_KEY, AGGREGATION_MODE ); return (price,); } 部署合约 运行 Protostar 部署命令,传入测试网: protostar deploy ./build/main.json --network testnet 部署完成后,我们可以在屏幕上看到合约地址和交易哈希,可以在 Voyager 上复制并与之交互。 从 Voyager 读取资产价格 完成合约部署后,我们可以通过 Voyager 与其交互。 首先调用 btc_price 函数: 其次是以太坊价格: 最后调用 Solana 价格: 你可以观察到他返回了 BTC、ETH 和 SOL 的价格(为本文撰写时价格)。 注意数字串的长度是 18 位小数。 最后 恭喜你已经完成了区块链预言机的域间通信!阅读 Maksimjeet Chowdhary 文章更深入了解预言机。 此外,Empiric 还提供更多资产价格信息,查看 Empiric 文档尝试构建更多,请注意部署前一定仔细检查预言机地址。 PS: Empiric 新宣布 VRF 功能,保持关注,未来将发布新功能指南文章。如果觉得本教程对你有帮助,转发分享给其他人吧~ ## Publication Information - [Starknet 中文](https://paragraph.com/@starknet-zh/): Publication homepage - [All Posts](https://paragraph.com/@starknet-zh/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@starknet-zh): Subscribe to updates - [Twitter](https://twitter.com/StarkNet_ZH): Follow on Twitter