【翻译】编写可升级的智能合约_NGP:TRUC价格

原文链接

当使用OpenZeppelinUpgrades编写可升级合约时,有一些在编写Solidity代码时需要记住一些注意事项。

值得一提的是,这些限制源于以太坊虚拟机的工作方式,并且适用于所有使用可升级合约的项目,而不仅仅是OpenZeppelinUpgrades。

初始化器

在编写Solidity合约使用OpenZeppelinUpgrades,无需任何修改,只需要修改构造函数。由于基于代理的可升级性系统的要求,可升级合约中不能使用构造函数。要了解这个限制背后的原因,请查看代理。

这意味着,当使用OpenZeppelin可升级的合约时,您需要将其构造函数改为一个常规函数,通常命名为initialize,在那里执行所有的初始化逻辑。

//NOTE:Donotusethiscodesnippet,it'sincompleteandhasacriticalvulnerability!pragmasolidity^0

}

然而,虽然Solidity确保一个构造函数constructor在合约的生命周期内只被调用一次,但一个普通函数可以被多次调用。为了防止一个合约被多次初始化,你需要添加一个检查来确保初始化函数只被调用一次。

链上期权协议Opyn上线基于ETH、UNI和WETH的5款期权产品:链上期权协议Opyn宣布上线5款新的期权产品,分别是12月4日到期行权价460美元的WETH看跌期权,12月25日到期行权价500美元的ETH看涨期权,12月25日到期行权价640美元的ETH看涨期权,12月25日到期行权价3.5美元的UNI看跌期权和12月25日到期行权价4美元的UNI看涨期权。[2020/11/20 21:27:48]

//contracts/MyContract

}

由于这种模式在编写可升级合约时非常常见,OpenZeppelinUpgrades提供了一个Initializable基础合约,它有一个initializermodifier来处理这个问题。

//contracts/MyContract

}

构造函数constructor和普通函数的另一个区别是,Solidity负责自动调用一个合约的所有基类的构造函数。在编写初始化器initializer时,你需要特别注意手动调用所有父合约的初始化器initializer。

//contracts/MyContract

}contractMyContractisBaseContract{uint256publicx;functioninitialize(uint256_x)publicinitializer{BaseContract

链上期权协议Opyn上线新的UNI看跌期权和看涨期权:链上期权协议Opyn官方宣布上线3款新的期权产品,分别是基于Uniswap原生代币UNI的看跌期权,到期日10月23日,行权价为3.5美元;UNI的看涨期权,到期日10月23日,行权价为8美元;WETH的看跌期权,到期日10月9日,行权价为330美元。[2020/9/25]

}

使用可升级的智能合约库

请记住,这个限制不仅会影响你的合约,还会影响你从库中导入的合约。例如考虑OpenZeppelin合约中的ERC20:该合约在其构造函数中初始化了token的名称、符号和小数位数。

//

这意味着你不应该在你的OpenZeppelinUpgrades项目中使用这些合约。相反,请确保使用...}

无论是使用OpenZeppelin合约还是其他智能合约库,都要确保软件包被设置为处理可升级合约。

在合约中了解更多关于OpenZeppelin合约可升级的信息:Contracts:UsingwithUpgrades。

避免在字段声明中使用初始值

Solidity允许在合约中声明字段时为其定义初始值。

contractMyContract{uint256publichasInitialValue=42;//equivalenttosettingintheconstructor}

分析 | 金色盘面:PROPY/ETH 持续走强:金色盘面分析师表示: PROPY/ETH平台整理,与多数币走势不同,他在触底后形成了一种稳步走高的趋势。[2018/8/5]

这相当于在构造函数中设置了这些值,因此,对于可升级的合约是无效的。请确保所有初始值都在如下所示初始化函数中设置;否则,任何可升级的实例都不会设置这些字段。

contractMyContractisInitializable{uint256publichasInitialValue;functioninitialize()publicinitializer{hasInitialValue=42;//setinitialvalueininitializer}}

注意定义_常量_状态变量还是可以的,因为编译器并没有为这些变量预留存储槽,每出现一次就会被相应的常量表达式所替代。所以下面的内容在OpenZeppelinUpgrades中仍然可以使用:

contractMyContract{uint256publicconstanthasInitialValue=42;//defineasconstant}

从合约代码中创建新实例

当从合约代码中创建一个新的合约实例时,这些创建直接由Solidity处理,而不是由OpenZeppelinUpgrades处理,这意味着这些合约将无法升级。

模因币LADYS或受Milady相关消息影响上涨超400%,DWF Labs昨日曾大量买入:5月11日消息,据 Dextools 数据显示,以 Milady Maker 系列 NFT 形象为灵感的模因币 LADYS 短时内大幅上涨,现报价 0.0(7)2169,40 分钟内涨幅超 400%。

此前报道,Twitter CEO 马斯克此前在社交媒体上发布推文附有 Milady Maker 系列 NFT 形象,并配文“There is no meme,I love you”。此后 Milady Maker 系列 NFT 地板价在 20 分钟内迅速翻倍,一度触及 7.1 ETH。

此前消息和数据显示,投资机构 DWF Labs 昨日将 13.5 ETH(约合 2.5 万美元)兑换 LADYS,当时价格约处于 0.0(8)25 左右价格区间。[2023/5/11 14:56:07]

例如,在下面的例子中,即使MyContract被部署为可升级,创建的token合约也是不可升级的:

//contracts/MyContract

}

潜在的不安全操作

在使用可升级的智能合约时,你将始终与合约实例进行交互,而不是底层逻辑合约。然而我们却无法阻止恶意行为者直接向逻辑合约发送交易。这不会构成威胁,因为逻辑合约状态的任何变化都不会影响你的合约实例,因为你的项目中从未使用过逻辑合约的存储。

然而,有一个例外。如果对逻辑合约的直接调用触发了自毁操作selfdestruct,那么逻辑合约就会被销毁,你的所有合约实例最终都会将所有的调用委托给一个地址,而不会有任何代码。这会破坏你项目中的所有合约实例。

如果逻辑合约中包含委托调用delegatecall操作,也可以达到类似的效果。如果可以将delegatecall变成一个包含自毁的恶意合约,那么调用合约将被破坏。

因此,在你的合约中不允许使用selfdestruct或delegatecall。

修改你的合约

在编写新版本的合约时,无论是由于新功能还是bug修复,都有一个额外的限制需要遵守:你不能改变合约状态变量的声明顺序,也不能改变它们的类型。你可以通过了解Proxies来阅读更多关于这个限制背后的原因。

警告违反这些存储布局限制中的任何一项,都会导致升级版的合约的存储值被混淆,并可能导致你的应用程序出现关键错误。这意味着,如果初始合约看起来像这样:

contractMyContract{uint256privatex;stringprivatey;}

那么不可以修改合约变量类型:

contractMyContract{stringprivatex;stringprivatey;}

也无法改变变量的声明顺序:

contractMyContract{stringprivatey;uint256privatex;}

不能在现有变量之前引入新的变量:

contractMyContract{bytesprivatea;uint256privatex;stringprivatey;}

也不能删除现有变量:

contractMyContract{stringprivatey;}

如果需要引入新的变量,请确保添加到原有变量的后面:

contractMyContract{uint256privatex;stringprivatey;bytesprivatez;}

注意,如果重命名一个变量,那么在升级后,它将保持与之前相同的值。如果新变量和旧变量的语义相同,那么这可能是我们所希望的行为:

contractMyContract{uint256privatex;stringprivatez;//startswiththevaluefrom`y`}

而如果你在合约的最后删除了一个变量,请注意存储不会被清除。随后的更新中如果增加一个新的变量,会导致该变量从被删除的变量中读取遗留的值:

contractMyContract{uint256privatex;}

升级到:

contractMyContract{uint256privatex;stringprivatez;//startswiththevaluefrom`y`}

注意,你也可能会因为改变合约的父合约而无意中改变合约的存储变量。例如,如果你有以下合约:

contractA{uint256a;}contractB{uint256b;}contractMyContractisA,B{}

然后通过调换基础合约的声明顺序或引入新的基础合约来修改MyContract,将改变变量的实际存储方式:

contractMyContractisB,A{}

如果集成合约有任何自己的变量,你也不能在基础合约中添加新的变量。鉴于以下情况:

contractBase{uint256base1;}contractChildisBase{uint256child;}

如果修改Base,增加一个额外的变量:

contractBase{uint256base1;uint256base2;}

然后,变量base2将被分配到上一个版本中那个child的槽位。一个变通的办法是在基础合约上声明未使用的变量,你可能会在未来想要扩展,作为"保留"这些槽位的一种手段。请注意,这个技巧不会增加gas使用量。

请戳↓“阅读原文”↓获取文中链接

免责声明:作为区块链信息平台,本站所发布文章仅代表作者个人观点,与链闻ChainNews立场无关。文章内的信息、意见等均仅供参考,并非作为或被视为实际投资建议。

本文来源于非小号媒体平台:

登链社区

现已在非小号资讯平台发布105篇作品,

非小号开放平台欢迎币圈作者入驻

入驻指南:

/apply_guide/

本文网址:

/news/9579149.html

免责声明:

1.资讯内容不构成投资建议,投资者应独立决策并自行承担风险

2.本文版权归属原作所有,仅代表作者本人观点,不代表非小号的观点或立场

上一篇:

币安为何推出第三条链?这对BNB意味着什么?

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

金宝趣谈

Gateio使用 Multicall 加速 DeFi 查询调用_ALL:COM

译文出自:登链翻译计划 译者:翻译小组 校对:Tiny熊 背景介绍 有时,从区块链获取数据的成本可能会非常高,不管是从请求花费的时间还是从发送的请求数量上来说,都是这样.

[0:0ms0-3:500ms