# Cairo 之旅 X：与 Empiric 预言机域间通信

By [Starknet 中文](https://paragraph.com/@starknet-zh) · 2022-11-14

---

> 作者：[Darlington Nnam](https://twitter.com/0xdarlington) 原文：[Journey Through Cairo X: Inter-realm Communications With Empiric Oracle](https://medium.com/@darlingtonnnam/journey-through-cairo-x-inter-realm-communications-with-empiric-oracle-917624d0cc88) 翻译及校对：[「StarkNet 中文社区」](https://twitter.com/StarkNet_ZH)

![](https://storage.googleapis.com/papyrus_images/d121db78be611154189a763f656c97d0bd458f584036b583384818b416b31176.png)

欢迎来到系列文章「Cairo 之旅」第十课！在上一课中，我们使用 Protostar 编写了第一个单元测试，今天我们将学习与 Empiric 预言机域间通信。

像往常一样，如果你是中途加入，建议从头开始看我们的文章。

区块链预言机 (Blockchain Oracle)
--------------------------

区块链预言机是个难以理解的概念尤其是那些初次听说的人们，今天就让我们深入了解。

![](https://storage.googleapis.com/papyrus_images/09fecaa8a71ab09177039c3538b2fce333bfb7c722200929bae60d2a7dd85ad6.png)

在希腊神话中，预言家是有特殊能力的人，也被称为祭司，他们拥有与神灵或精神境界互动和交流的能力。他们经常被当作神灵的传声筒，作为了解神灵的想法的唯一方式。

当把预言机概念应用于区块链时，我们就得到了区块链预言机，那么能否将其理解为区块链预言机启用跨领域通信呢？

让我们继续深入研究。

### 区块链是确定性的

区块链被设定为确定性的，区块链被建立成一个独立的系统（想象没有互联网连接的计算机），并就其分类帐中的数据达成共识。

尽管它在某些方面发挥了重要作用，如有助于区块链获得高度的准确性或确定性，从而使其成为无需信任的系统，但它对智能合约的实现提出了很多限制。

大规模采用是我们所期盼的核心目标之一，当我们无法与外界交互时怎么实现这一目标呢？金融智能合约需要市场信息来确定结算，保险智能合约需要物联网 (Internet of Things) 等。

最大的问题是如何在不牺牲区块链确定性的前提下与外界交互？当然不能只依靠一个中心化实体来提供信息，这否定了去中心化的核心原则，因为中心化实体可能遭遇突发停电，或被破坏的情况。

这些正是区块链预言机试图解决的问题，为区块链上的智能合约运行提供去中心化的方式，使其能在不牺牲区块链确定性的前提下与外界有效交互。

阅读 [Chainlink 文章](https://blog.chain.link/what-is-the-blockchain-oracle-problem/?_ga=2.213702358.373816698.1664492959-1994574895.1661908390)深入了解预言机如何工作。

Empiric — 在 StarkNet 上重塑预言机
---------------------------

就像 [**Chainlink**](https://chain.link/) 解决了以太坊预言机难题，[**Empiric**](https://empiric.network/) 也在尝试解决 StarkNet 预言机问题。

利用 ZK 技术创建起一个透明公开、可组合、去中心化的架构。

今天我们深入学习预言机，查看其是如何运行的，并利用 Empiric 的喂价功能来构建第一个混合智能合约 (Hybrid Smart Contract)。

### 准备工作

首先需要用 [Protostar 建立本地环境](https://medium.com/@darlingtonnnam/journey-through-cairo-i-setting-up-protostar-and-argentx-for-local-development-ba40ae6c5524)。

### 项目描述

构建一个利于用户获取 BTC、ETH 和 SOL 代币价格的简易项目。

### 必要条件

具备[编写 StarkNet 合约](https://medium.com/@darlingtonnnam/journey-through-cairo-viii-writing-and-deploying-your-first-starknet-contract-with-protostar-620ff76062fa)的基础知识。

### 项目初始化

Protostar 设置完后，通过以下指令运行新项目：

    protostar init
    

完成后，按照要求输入项目名称和库名称成功创建一个新项目。

编写合约
----

[部署 StarkNet 合约](https://medium.com/@darlingtonnnam/journey-through-cairo-viii-writing-and-deploying-your-first-starknet-contract-with-protostar-620ff76062fa)中概述了大部分代码和流程，在此只讲解部分代码。

### 导入

    %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")
    

定义合约中所需的五个常量：

1.  EMPIRIC\_ORACLE\_ADDRESS：指定部署 Empiric 合约地址。
    
2.  ETH\_KEY：eth/usd 小写 utf8 编码字符串。作为一个指针来通知预言机你需要什么交易对。
    
3.  BTC\_KEY：btc/usd 小写 utf8 编码字符串。
    
4.  SOL\_KEY：sol/usd 小写 utf8 编码字符串。
    
5.  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 与其交互。

![](https://storage.googleapis.com/papyrus_images/e0eec5ccc961e418efa6b11556cc0590cdebb8467e7094d497d7f1f267dc208d.png)

首先调用 btc\_price 函数：

![](https://storage.googleapis.com/papyrus_images/4895f8f8bad30751383f252574e0beeac5ce94a43fab3b115bc39a6394fec5be.png)

其次是以太坊价格：

![](https://storage.googleapis.com/papyrus_images/4a4bc7da8fa02ae9cca80dc7c17e154d781676d73535d77710754d24964cc6c0.png)

最后调用 Solana 价格：

![](https://storage.googleapis.com/papyrus_images/ec4b9ca52440f0a3b35a6b24fb71c2f26f20e30903e176ca4cda0009f338efac.png)

你可以观察到他返回了 BTC、ETH 和 SOL 的价格（为本文撰写时价格）。

注意数字串的长度是 18 位小数。

最后
--

恭喜你已经完成了区块链预言机的域间通信！阅读 [Maksimjeet Chowdhary 文章](https://hackernoon.com/oracles-on-starknet)更深入了解预言机。

此外，**Empiric** 还提供更多资产价格信息，查看 [Empiric 文档](https://docs.empiric.network/)尝试构建更多，请注意部署前一定仔细检查预言机地址。

**_PS: Empiric 新宣布 VRF 功能，保持关注，未来将发布新功能指南文章。如果觉得本教程对你有帮助，转发分享给其他人吧~_**

---

*Originally published on [Starknet 中文](https://paragraph.com/@starknet-zh/cairo-x-empiric)*
