币圈信息网 币圈新闻 慢雾:DeFi 当红项目 YAM 闪电折戟,一行代码如何蒸发数亿美元?

慢雾:DeFi 当红项目 YAM 闪电折戟,一行代码如何蒸发数亿美元?

当红流动性挖矿项目 YAM 创始人披露该项目合约漏洞,慢雾技术详解漏洞细节。原文标题:《DeFi Y

当红震动性挖矿名目 yam 创办人表露该名目合约缺点,慢雾本领详解缺点详细比特币中国平台

原文题目:《defi yam比特币挖矿什么意思,一条龙代码怎样挥发数亿美元?》 撰文:yudan @ 慢雾安定共青团和少先队

据区块链搜集动静, 2020 年 8 月 13 日,著名以太坊 defi 名目 yam 官方经过 twitter 发文表白创造合约中生存缺点,24 钟点内价钱暴跌 99% 比特币钱包。慢雾安定共青团和少先队在收到谍报后赶快举行了关系的跟进及领会,以次是精细的本领详细。

爆发了什么比特币价格今日行情

之上是 yam 官方对此次事变的 简略证明比特币行情走势图

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

大略来说即是官方在合约中创造控制安排供给量的因变量爆发了题目,这个题目引导过剩的 yam 代币放进了 yam 的 reserves 合约中,而且即使不矫正这个题目,将会引导 yam 的后续处置变为不大概比特币美。同声,官方给出了此次缺点的简直题目代码,如次:

从上海图书馆可知,因为源代码不典型,yam 合约在安排 totalsupply 的功夫,本应将结果的截止除以 base 变量,然而在本质开拓进程中却忽视了,引导 totoalsupply 计划不精确,比从来的值要大 10^18 倍比特币交易。然而代币供给量题目和处置是如何扯上联系呢?这须要咱们对准代码做进一步的领会。

yam 会形成还好吗比特币之父

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

为了深刻领会此次缺点形成的感化,须要对 yam 名目代码举行深刻的领会比特币之父。按照官方给出的题目代码及名目 github 地方(https://github.com/yam-finance/yam-protocol),不妨定位出安排供给量的rebase因变量坐落 yamdelegator.sol 合约中,简直代码如次:

function rebase( uint256 epoch, uint256 indexdelta, bool positive ) external returns (uint256) { epoch; indexdelta; positive; delegateandreturn(); }

经过盯梢rebase因变量打击比特币挖矿,创造rebase因变量最后挪用了 delegateandreturn 因变量,代码如次:

function delegateandreturn() private returns (bytes memory) { (bool success, ) = implementation.delegatecall(msg.data); assembly { let free_mem_ptr := mload(0x40) returndatacopy(free_mem_ptr, 0, returndatasize) switch success case 0 { revert(free_mem_ptr, returndatasize) } default { return(free_mem_ptr, returndatasize) } } }

经过领会代码,不妨创造 delegateandreturn 因变量最后运用 delegatecall 的办法挪用了 implementation 地方中的论理,也即是说,这是一个可晋级的合约模子四川比特币矿场集体断电。而真实的rebase论理坐落 yam.sol 中 , 连接跟进 rebase 因变量的简直论理,如次:

function rebase( uint256 epoch, uint256 indexdelta, bool positive ) external onlyrebaser returns (uint256) { if (indexdelta == 0) { emit rebase(epoch, yamsscalingfactor, yamsscalingfactor); return totalsupply; } uint256 prevyamsscalingfactor = yamsscalingfactor; if (!positive) { yamsscalingfactor = yamsscalingfactor.mul(base.sub(indexdelta)).div(base); } else { uint256 newscalingfactor = yamsscalingfactor.mul(base.add(indexdelta)).div(base); if (newscalingfactor <_maxscalingfactor()) { yamsscalingfactor = newscalingfactor; } else { yamsscalingfactor =_maxscalingfactor(); } } //slowmist// 题目代码 totalsupply = initsupply.mul(yamsscalingfactor); emit rebase(epoch, prevyamsscalingfactor, yamsscalingfactor); return totalsupply; }}

经过领会最后的rebase因变量的论理,不难发新颖码中按照 yamsscalingfactor 来对 totalsupply 举行安排,因为 yamsscalingfactor 是一个高精度的值,在安排实行后该当除以 base 往返除计划进程中的精度,赢得精确的值比特币价格今日行情。然而名目方在对 totalsupply 举行安排时,竟忘怀了对计划截止举行安排,引导了 totalsupply 不料变大,计划堕落误的截止。

领会到这边还没中断,要将缺点和社区处置关系起来,须要对代码进前进一步的领会比特币交易网。经过查看rebase因变量的化装器,不难创造此处控制了只能是 rebaser 举行挪用。而 rebaser 是 yam 顶用与实行供给量关系论理的合约,也即是说,是 rebaser 合约最后挪用了 yam.sol 合约中的rebase因变量。经过盯梢关系代码,创造 rebaser 合约中对应供给量安排的论理为rebase因变量,代码如次:

function rebase() public { // eoa only require(msg.sender == tx.origin); // ensure rebasing at correct time _inrebasewindow(); // this comparison also ensures there is no reentrancy. require(lastrebasetimestampsec.add(minrebasetimeintervalsec) < now); // snap the rebase time to the start of this window. lastrebasetimestampsec = now.sub( now.mod(minrebasetimeintervalsec)).add(rebasewindowoffsetsec); epoch = epoch.add(1); // get twap from uniswap v2; uint256 exchangerate = gettwap(); // calculates % change to supply (uint256 offpegperc, bool positive) = computeoffpegperc(exchangerate); uint256 indexdelta = offpegperc; // apply the dampening factor. indexdelta = indexdelta.div(rebaselag); yamtokeninterface yam = yamtokeninterface(yamaddress); if (positive) { require(yam.yamsscalingfactor().mul(uint256(10**18).add(indexdelta)).div(10**18) < yam.maxscalingfactor(), \”new scaling factor will be too big\”); } //slowmist// 取暂时 yam 代币的供给量 uint256 currsupply = yam.totalsupply(); uint256 mintamount; // reduce indexdelta to account for minting //slowmist// 计划要安排的供给量 if (positive) { uint256 mintperc = indexdelta.mul(rebasemintperc).div(10**18); indexdelta = indexdelta.sub(mintperc); mintamount = currsupply.mul(mintperc).div(10**18); } // rebase //slowmist// 挪用 yam 的 rebase 论理 uint256 supplyafterrebase = yam.rebase(epoch, indexdelta, positive); assert(yam.yamsscalingfactor() <= yam.maxscalingfactor()); // perform actions after rebase //slowmist// 加入安排论理 afterrebase(mintamount, offpegperc); }

经过领会代码,不妨创造因变量在举行了一系列的查看后,开始获得了暂时 yam 的供给量,计划此次的铸币数目,而后再挪用 yam.sol 中的rebase因变量对 totalsupply 举行安排,也即是说 rebase 事后的对 totalsupply 的感化要鄙人一次挪用 rebaser 合约的rebase因变量才会奏效比特币交易所。结果rebase因变量挪用了 afterrebase 因变量。咱们连接跟进 afterrebase 因变量中的代码:

function afterrebase( uint256 mintamount, uint256 offpegperc ) internal { // update uniswap uniswappair(uniswap_pair).sync(); //slowmist// 经过 uniswap 购置 ycrv 代币 if (mintamount > 0) { buyreserveandtransfer( mintamount, offpegperc ); } // call any extra functions //slowmist// 社区处置挪用 for (uint i = 0; i < transactions.length; i++) { transaction storage t = transactions[i]; if (t.enabled) { bool result = externalcall(t.destination, t.data); if (!result) { emit transactionfailed(t.destination, i, t.data); revert(\”transaction failed\”); } } } }

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

经过领会创造, afterrebase 因变量重要的论理在 buyreserveandtransfer 因变量中,此因变量用来将增发出来的代币的一局部用来到 uniswap 中购置 ycrv 代币比特币暴涨。盯梢 buyreserveandtransfer 因变量,代码如次:

*

function buyreserveandtransfer( uint256 mintamount, uint256 offpegperc ) internal { uniswappair pair = uniswappair(uniswap_pair); yamtokeninterface yam = yamtokeninterface(yamaddress); // get reserves (uint256 token0reserves, uint256 token1reserves, ) = pair.getreserves(); // check if protocol has excess yam in the reserve uint256 excess = yam.balanceof(reservescontract); //slowmist// 计划用来 uniswap 中对换的 yam 数目 uint256 tokens_to_max_slippage = uniswapmaxslippage(token0reserves, token1reserves, offpegperc); univars memory univars = univars({ yamstouni: tokens_to_max_slippage, // how many yams uniswap needs amountfromreserves: excess, // how much of yamstouni comes from reserves minttoreserves: 0 // how much yams protocol mints to reserves }); // tries to sell all mint + excess // falls back to selling some of mint and all of excess // if all else fails, sells portion of excess // upon pair.swap, `uniswapv2call` is called by the uniswap pair contract if (istoken0) { if (tokens_to_max_slippage > mintamount.add(excess)) { // we already have performed a safemath check on mintamount+excess // so we dont need to continue using it in this code path // can handle selling all of reserves and mint uint256 buytokens = getamountout(mintamount + excess, token0reserves, token1reserves); univars.yamstouni = mintamount + excess; univars.amountfromreserves = excess; // call swap using entire mint amount and excess; mint 0 to reserves pair.swap(0, buytokens, address(this), abi.encode(univars)); } else { if (tokens_to_max_slippage > excess) { // uniswap can handle entire reserves uint256 buytokens = getamountout(tokens_to_max_slippage, token0reserves, token1reserves); // swap up to slippage limit, taking entire yam reserves, and minting part of total //slowmist// 将过剩代币铸给 reserves 合约 univars.minttoreserves = mintamount.sub((tokens_to_max_slippage – excess)); //slowmist// uniswap 代币调换 pair.swap(0, buytokens, address(this), abi.encode(univars)); } else { // uniswap cant handle all of excess uint256 buytokens = getamountout(tokens_to_max_slippage, token0reserves, token1reserves); univars.amountfromreserves = tokens_to_max_slippage; univars.minttoreserves = mintamount; // swap up to slippage limit, taking excess – remainingexcess from reserves, and minting full amount // to reserves pair.swap(0, buytokens, address(this), abi.encode(univars)); } } } else { if (tokens_to_max_slippage > mintamount.add(excess)) { // can handle all of reserves and mint uint256 buytokens = getamountout(mintamount + excess, token1reserves, token0reserves); univars.yamstouni = mintamount + excess; univars.amountfromreserves = excess; // call swap using entire mint amount and excess; mint 0 to reserves pair.swap(buytokens, 0, address(this), abi.encode(univars)); } else { if (tokens_to_max_slippage > excess) { // uniswap can handle entire reserves uint256 buytokens = getamountout(tokens_to_max_slippage, token1reserves, token0reserves); // swap up to slippage limit, taking entire yam reserves, and minting part of total //slowmist// 增发的过剩的代币给 reserves 合约 univars.minttoreserves = mintamount.sub( (tokens_to_max_slippage – excess)); // swap up to slippage limit, taking entire yam reserves, and minting part of total //slowist// 在 uniswap 中举行对换比特币美,并最后挪用 rebase 合约的 uniswapv2call 因变量 pair.swap(buytokens, 0, address(this), abi.encode(univars)); } else { // uniswap cant handle all of excess uint256 buytokens = getamountout(tokens_to_max_slippage, token1reserves, token0reserves); univars.amountfromreserves = tokens_to_max_slippage; univars.minttoreserves = mintamount; // swap up to slippage limit, taking excess – remainingexcess from reserves, and minting full amount // to reserves pair.swap(buytokens, 0, address(this), abi.encode(univars)); } } } }

经过对代码领会比特币跌破,buyreserveandtransfer 开始管帐算在 uniswap 顶用于对换 ycrv 的 yam 的数目,即使该数目少于 yam 的铸币数目,则会将过剩的增发的 yam 币给 reserves 合约,这一步是经过 uniswap 合约挪用rebase合约的 uniswapv2call 因变量实行的,简直的代码如次:

function uniswapv2call( address sender, uint256 amount0, uint256 amount1, bytes memory data ) public { // enforce that it is coming from uniswap require(msg.sender == uniswap_pair, \”bad msg.sender\”); // enforce that this contract called uniswap require(sender == address(this), \”bad origin\”); (univars memory univars) = abi.decode(data, (univars)); yamtokeninterface yam = yamtokeninterface(yamaddress); if (univars.amountfromreserves > 0) { // transfer from reserves and mint to uniswap yam.transferfrom(reservescontract, uniswap_pair, univars.amountfromreserves); if (univars.amountfromreserves < univars.yamstouni) { // if the amount from reserves > yamstouni, we have fully paid for the ycrv tokens // thus this number would be 0 so no need to mint yam.mint(uniswap_pair, univars.yamstouni.sub(univars.amountfromreserves)); } } else { // mint to uniswap yam.mint(uniswap_pair, univars.yamstouni); } // mint unsold to mintamount //slowmist// 将过剩的 yam 代币散发给 reserves 合约 if (univars.minttoreserves > 0) { yam.mint(reservescontract, univars.minttoreserves); } // transfer reserve token to reserves if (istoken0) { safeerc20.safetransfer(ierc20(reservetoken), reservescontract, amount1); emit treasuryincreased(amount1, univars.yamstouni, univars.amountfromreserves, univars.minttoreserves); } else { safeerc20.safetransfer(ierc20(reservetoken), reservescontract, amount0); emit treasuryincreased(amount0, univars.yamstouni, univars.amountfromreserves, univars.minttoreserves); } }

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

领会到这边什么是比特币,一个完备的rebase过程就实行了,你大概看得很懵,咱们用大略的过程图简化下:

也即是说比特币怎么买,历次的rebase,即使有过剩的 yam 代币,那些代币将会流到 reserves 合约中,那这和社区处置的联系是什么呢?

经过领会名目代码比特币跌破,创造处置关系的论理在 yamgovernoralpha.sol 中,个中倡导提案的因变量为 propose,简直代码如次:

function propose( address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description ) public returns (uint256) { //slowmist// 校验提案倡导者的票数占比 require(yam.getpriorvotes(msg.sender, sub256(block.number, 1)) > proposalthreshold(), \”governoralpha::propose: proposer votes below proposal threshold\”); require(targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, \”governoralpha::propose: proposal function information arity mismatch\”); require(targets.length != 0, \”governoralpha::propose: must provide actions\”); require(targets.length <= proposalmaxoperations(), \”governoralpha::propose: too many actions\”); uint256 latestproposalid = latestproposalids[msg.sender]; if (latestproposalid != 0) { proposalstate proposerslatestproposalstate = state(latestproposalid); require(proposerslatestproposalstate != proposalstate.active, \”governoralpha::propose: one live proposal per proposer, found an already active proposal\”); require(proposerslatestproposalstate != proposalstate.pending, \”governoralpha::propose: one live proposal per proposer, found an already pending proposal\”); } uint256 startblock = add256(block.number, votingdelay()); uint256 endblock = add256(startblock, votingperiod()); proposalcount++; proposal memory newproposal = proposal({ id: proposalcount, proposer: msg.sender, eta: 0, targets: targets, values: values, signatures: signatures, calldatas: calldatas, startblock: startblock, endblock: endblock, forvotes: 0, againstvotes: 0, canceled: false, executed: false }); proposals[newproposal.id] = newproposal; latestproposalids[newproposal.proposer] = newproposal.id; emit proposalcreated( newproposal.id, msg.sender, targets, values, signatures, calldatas, startblock, endblock, description ); return newproposal.id; }

经过领会代码如何获得比特币,不妨发此刻倡导提案时,须要提案倡导人具有确定额度的票权力,这个值必需大于 proposalthreshold 计划得来的值,简直代码如次:

function proposalthreshold() public view returns (uint256) { return safemath.div(yam.initsupply(), 100); } // 1% of yam

也即是说提案倡导人的票权必需大于 initsupply 的 1% 本领倡导提案比特币挖矿什么意思。那 initsupply 受什么感化呢?谜底是 yam 代币的 mint 因变量,代码如次:

*

function mint(address to, uint256 amount) external onlyminter returns (bool) { _mint(to, amount); return true; } function_mint(address to, uint256 amount) internal { // increase totalsupply totalsupply = totalsupply.add(amount); // get underlying value uint256 yamvalue = amount.mul(internaldecimals).div(yamsscalingfactor); // increase initsupply initsupply = initsupply.add(yamvalue); // make sure the mint didnt push maxscalingfactor too low require(yamsscalingfactor <=_maxscalingfactor(), \”max scaling factor too low\”); // add balance _yambalances[to] =_yambalances[to].add(yamvalue); // add delegates to the minter _movedelegates(address(0),_delegates[to], yamvalue); emit mint(to, amount); }

从代码可知,mint 因变量在历次铸币时城市革新 initsupply 的值,而这个值是按照 amount 的值来计划的,也即是铸币的数目比热比价格实时行情

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

此刻比特币交易所,咱们仍旧领会完一切的过程了,剩下的即是把一切的领会串起来,看看这次的缺点对 yam 爆发了什么感化,对下文的过程图做拓展,形成底下如许:

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

所有事变的领会如上海图书馆,因为rebase的功夫取的是上一次的 totalsupply 的值,以是计划缺点的 totalsupply 的值并不会登时经过 mint 效率到 initsupply 上,以是鄙人一次rebase前,社区仍有时机补救这个缺点,缩小丢失比特币最新价格行情。然而一旦下一次rebase实行,所有错误将会变得没辙补救。

慢雾:defi 当红名目 yam 闪电折戟,一条龙代码怎样挥发数亿美元?

经过查问 etherscan 上 yam 代币合约的关系消息,不妨看到 totalsupply 仍旧到了一个特殊大的值,而 initsupply 还未遭到感化比特币暴涨

前事不忘比特币之父,后事之师

这次事变中官方仍旧给出了简直的建设计划,这边不复赘述比特币是什么。这次的事变充溢表露了一经审批 defi 合约中湮没的宏大危害,固然 yam 开拓者仍旧在 github 中表白 yam 合约的很多代码是参考了过程充溢审批的 defi 名目如 compound、ampleforth、synthetix 及 yearn/yfi,然而仍无可制止地爆发了预见除外的危害。

defi 名目 yam finance (yam) 中心开拓者 belmore 在推特上表白:「抱歉,大师比特币价格今日行情。我波折了。感谢尔等即日的大举扶助。我太忧伤了。」然而覆水仍旧难收,在此,慢雾安定共青团和少先队给出如次倡导:

1、因为 defi 合约的莫大搀杂性,任何 defi 名目都需在过程专科的安定共青团和少先队充溢审批后再举行上线,贬低合约发交易外的危害 关于防范比特币风险的通知。审批可接洽慢雾安定共青团和少先队([email protected])

2、名目中去重心化治理当循规蹈矩,在名目发端阶段,须要树立符合的权力以防爆发黑天鹅事变中国比特币

根源链接比特币价格今日:mp.weixin.qq.com

本文来自网络,不代表币圈信息网立场,转载请注明出处:http://www.lpbwg.com/32703.html

作者: bqxxw

返回顶部