Diamond

Posted on Nov 13, 2022Read on Mirror.xyz

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

作者: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")

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

  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 与其交互。

首先调用 btc_price 函数:

其次是以太坊价格:

最后调用 Solana 价格:

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

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

最后

恭喜你已经完成了区块链预言机的域间通信!阅读 Maksimjeet Chowdhary 文章更深入了解预言机。

此外,Empiric 还提供更多资产价格信息,查看 Empiric 文档尝试构建更多,请注意部署前一定仔细检查预言机地址。

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