oracle uniall实例,Uniswap V2 Oracle和链上累计价格存储证明的结合使用

Uniswap V2发布了许多新功用,包括:

·

· 内置多跳路由(ETH->DAI->MKR->USDT,假如这是ETH->USDT的

· ERC777兼容性

· 累积价钱Oracle

在本文中,我们将讨论此“累加价钱Oracle”其任务方式,如何运用它,并引见一个Solidity库,可以用来将这个Oracle集成到您本人的

假如您曾经理解本文次要的想法,你可以在这里找到代码示例和solidity库:https://github.com/Keydonix/uniswap-oracle。

虽然我们通常以为oracle

为了阐明Uniswap V2经过这一新的Oracle功用处理的成绩,让我们首先讨论Uniswap V1的成绩。

a8bd29993c8dd8b9c11fe2217f45009e.png

不要将Uniswap V1用作Oracle

Uniswap团队从未将Uniswap V1推行为可行的链上Oracle。正是由于Uniswap复杂、无答应、链上、面向市场的功用,才吸引了有发明力的人将其作为一个全体来运用。Uniswap V1 oracle的警报器很复杂:

uint256 tokenPrice = token.balanceOf(uniswapMarket) /

address(uniswapMarket).balance

由于目前Uniswap V1市场的“价钱”只是

Uniswap V1的成绩在于价钱反应是即时的,并且很容易在很短的

// send 100 ether and receive some number of tokens

uniswapMarket.ethToTokenSwapInput.value(100 ether)(100 ether);

exploitTarget.doSomethingThatUsesUniswapV1AsOracle();

// send all the tokens we received above back

uniswapMarket.tokenToEthSwapInput(token.balanceOf(address(this));

在下面的攻击中,您将向活动性提供者领取十分大批的以太币(约0.6 ETH)的费用(双向为0.3%)。但是当调用exploitTarget时,它会以为令牌比实践值钱得多。假如exploitTarget运用Uniswap V1 oracle来确保您存入的抵押品价值足以提取其他代币,那么该零碎将允许您提取比存款凭单多得多的借出代币。

Uniswap V2如何像Oracle一样任务

在下面的例子中,Uniswap V1价钱读取是有成绩的,由于它们是即时的。V2部署了一个聪明的零碎,用于将价钱工夫数据记载在链上,这种方式在短工夫内操作本钱很高,并且不能够在单个买卖中停止操作。经过运用“累计”价钱工夫值,可以将价钱的可用工夫加权为一个特殊值,每次代币掉期都会破费大批的自然气来坚持这些值的同步。

以下是Uniswap市场代码片段:

留意:与V1不同,V2是两个代币之间的市场。在外部,这些令牌中的一个需求表示为token0,另一个表示为token1。他们的余额由相应的reserve0和reserve1跟踪。Uniswap Docs具有有关令牌排序的更多信息。

contract UniswapV2Pair {

// Contract Storage Variables:

uint public price0CumulativeLast;

uint public price1CumulativeLast;

// The only place these storage variables are updated:

function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {

uint32 timeElapsed = blockTimestamp – blockTimestampLast;

if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {

price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;

price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;

}

blockTimestampLast = blockTimestamp;

}

}

price(0 | 1)CumulativeLast是独立的存储变量,它们累积“ price-time”。UQ112x112使代码有点难以阅读,但在概念上并不重要;它只充任高精度除法的包装器。这些累积弹性值的“0”和“1”版本之间的独一区别是价钱的方向。

price0CumulativeLast是“以token1计价的token0的价钱”

price1CumulativeLast是“以token0计价的token1的价钱”

由于在停止这种累加时数学运算的方式,price0CumulativeLast不是price1CumulativeLast的倒数。关于本文档的其他局部,我们将仅援用price0CumulativeLast,但异样适用于这两个值。另外,price0CumulativeLast不一定在每个区块上都是最新的,因而您要么需求在市场上运转sync(),要么本人调整值。

price0CumulativeLast是一个值,它只更新区块上的第一个事务,取最初一个已知的reserve0和reserve1值(token0和token1的令牌余额),计算它们的比率(price),并按price0CumulativeLast上次更新后的秒数停止缩放。price0CumulativeLast是一个每秒钟按两个储量的比率递增的值。要将此值转换回价钱,需求两个工夫点值price0CumulativeLast,运用以下公式:

(price0CumulativeLATEST — price0CumulativeFIRST) /

(timestampOfLATEST — timestampOfFIRST)

经过将两个样本中价钱累计的差值除以这两个样本之间的秒数,进程被逆转,后果就是该时段的工夫加权价钱。您选择的窗口是一个重要的平安思索要素:

· 两个样本之间的秒数越少,更新的工夫就越多,但更易于操作。

· 两个样本之间的秒数越长,更新的工夫越少,但操作起来就越困难。

在防窜改和最新之间找到正确的均衡点应该细心思索您的项目。

如今我们曾经有了计算这个价钱的公式,但依然存在一个成绩:如何检索链上的历史价钱累积信息?

运用智能

应用V2作为链上的Oracle,需求“

检索每个值的以后值都很复杂(block.timstamp和uniswapMarket.price0CumulativeLast()),但是如何检索旧值呢?最直接的办法是部署一个智能合约,该合约将price0CumulativeLast和工夫戳的以后值记载到其本人的存储中,以供当前调用以作为历史值。虽然这可行,但它有一些缺陷:

· 必需活期调用以存储快照值,假如您希望该价钱馈送在未来继续可用。

· 假如不活期调用,则必需提早方案事务,首先存储以后值,等候一段工夫,然后启动运用该历史值的事务。

你总是在某种水平上鼓励机器人不时更新存储值(机器人费用来自零碎中其他中央的利润),或许要求用户发送两个事务,一个用来获取累计值,将他们希望执行的事务延迟一些十分重要的工夫,以到达价钱馈送均匀值所需的秒数。

假如你对为机器人设计经济零碎不感兴味,并且你疑心用户能否情愿等候发送两个买卖,有一个更好的办法来应用Uniswap V2作为价钱来源:Merkle Patricia Proof!

应用存储证明检索历史累计值

以太坊合约形态存储在“ Merkle Trie”中,这是一种特殊的数据构造,它允许一个32字节的哈希值代表每个以太坊合约中的每个存储值(具有独自的收据和买卖数据尝试)。这个32字节的值称为stateRoot,是每个以太坊块(以及您能够更熟习的块,例如块号,块哈希和工夫戳)的属性。

运用以太坊节点的JSON-RPC接口,您可以调用eth_getProof来检索无效负载,当与该stateRoot值结合运用时,可以证明存储插槽B上的地址A的值为C。

运用链上逻辑,可以将stateRoot和存储证明结合起来以验证存储插槽的值。假如我们针对Uniswap V2市场和price0CumulativeLast的存储插槽,则可以完成所需的基于证明的历史查找。

但是stateRoot查找不能作为EVM操作码运用。独一相关的操作码是BLOCKHASH,它采用blockNumber并前往32字节的区块哈希。块的blockhash是一个复杂的Keccak256哈希,它具有rlp编码的一切各种属性。经过提供一个区块的一切属性(包括stateRoot),我们可以经过散列并将其与链上blockHash查找停止比拟,从而验证原始块数据能否无效。验证之后,我们便可以运用区块的必需属性(工夫戳和stateRoot)。

// NOTE: Non-functional pseudo code

function verifyBlock(parentBlock, stateRoot, blockNumber, timestamp, …) returns (bool) {

bytes32 _realBlockHash = blockhash(blockNumber);

bytes32 _proposedBlockHash = keccek256(rlpEncode(parentBlock, stateRoot, blockNumber, timestamp, …));

return _proposedBlockHash == _realBlockHash;

}

1. 像下面这样的函数可以验证完好块的详细信息,并确认该块的一切字段都是正确的

2. 运用stateRoot(下面已验证)解析提供的证明(来自JSON-RPC getProof调用)从该块检索历史存储值

3. 从Uniswap market获取以后价钱0累积最新值

4. 经过将price0CumulativeLast中的增量除以自验证工夫戳以来的秒数,计算所提供块(来自验证的工夫戳)和如今之间的均匀价钱。

此时,您可以在地道可依据市场静态从完全去中心化的零碎中,在一段可配置的工夫内均匀取得价钱。为了让这个价钱反应被操纵,攻击者不只需求向一个方向推进这个价钱,他们还需求在区块之间长工夫坚持价钱不变,让任何买家都无机会购置价钱偏低的资产,这反过去又会纠正价钱下跌。

留意:链上BLOCKHASH查找仅适用于过来256个区块,可用于存储证明的最旧块必需在事务落入链上时位于最初256个区块之内。

引见Uniswap Oracle库

以下策略由大批客户端代码(用于处置证明)和少量相当复杂的Solidity组成,包括YUL/assembly和Merkle Trie验证。作为Keydonix开发团队的一员,Micah Zoltu和我开发并发布了Uniswap-Oracle,这是一个Solidity库,使其他智能合约可以应用此oracle功用。

要与您本人的智能合约集成,只需复杂地从根本合约UniswapOracle.sol(contract HelloWorld is UniswapOracle)承继,您的合约将承继getPrice函数:

function getPrice(

IUniswapV2Pair uniswapV2Pair,

address denominationToken,

uint8 minBlocksBack,

uint8 maxBlocksBack,

ProofData memory proofData)

public view

returns (

uint256 price,

uint256 blockNumber

)

需求拜访此Uniswap price的您本人的函数将需求接纳此证明数据作为参数传递给此外部getPrice函数调用。请参阅Uniswap Oracle自述文件.me集成文档。

Uniswap-Oracle库未经审核。任何对主网有价值的使用顺序都应该停止片面审计;请确保您的使用顺序的审计也包括Uniswap的Oracle代码。

原创文章,作者:区块腾,如若转载,请注明出处:http://www.qukuaiteng.com/3531840.html 《Uniswap V2 Oracle和链上累计价格存储证明的结合使用》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值