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 功能,保持关注,未来将发布新功能指南文章。如果觉得本教程对你有帮助,转发分享给其他人吧~

Subscribe to Starknet 中文
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.