一文读懂如何实现智能合约迁移

.wqpc_wechat_view *{max-width: 100%!important;box-sizing:
border-box!important;-webkit-box-sizing: border-box!important;
word-wrap: break-word!important;} 微信号 功能介绍
智能合约也会遭受损害:比如存在漏洞、合约拥有者的钱包被盗,或者由于某种错误设置导致死锁。如果你为自己的企业开发了智能合约,那么你必须做好应对类似事件的预案。在很多情况下,唯一的解决方案是部署一个新的合约实例,并将数据迁移到该实例中。如果你打算开发一个可升级的合约,迁移程序(migration
procedure)将有助于免除可升级性机制(upgradability
mechanism)的潜在危险[1]。本文旨在为你详细讲解如何实现合约迁移。你需要嵌入合约迁移功能即使是零漏洞的合约也可能被窃取的私钥劫持。先前的Bancor
[2] 和 KICKICO
[3]黑客事件表明:攻击者可以损害智能合约钱包。在这些攻击中,即使合约具备可升级性机制,也可能无法修复已部署的智能合约。唯一的解决办法是重新部署并正确初始化新的合约实例,以便为用户恢复功能。因此,所有智能合约开发者必须在合约设计阶段整合一个迁移程序。此外,企业必须做好在合约损害事件发生时实施迁移的准备。迁移过程有两个步骤:恢复要迁移的数据将数据写入新合约我们来深入探讨其中的细节、成本和操作后果。第一步:数据恢复你需要从区块链的某个特定区块中读取数据。要想从损害事件(黑客攻击或故障)中恢复数据,你需要在事件发生之前使用这个区块,或者过滤攻击者的操作。如果可以的话,请暂停合约。这对于用户来说更加透明公平,并能阻止攻击者盯上那些对迁移不知情的用户。数据恢复的具体操作取决于你的数据结构。对于简单类型的公共变量(public
variables,例如uint或address)来说,通过它们的getter来检索特定值就可以了。而对于私有变量(private
variables),你可以依赖事件,也可以计算变量的内存偏移量,然后使用
getStorageAt [4]
函数检索它的值。由于元素的数量是已知的,因此数组也很容易恢复。上述技术你都可以使用。至于映射(mappings)的话,情况有点复杂。由于键(Keys)在映射过程中不会被存储,所以你需要将它们进行恢复才能访问对应的值(Values)。为了简化链下追踪的过程,我们建议在值被存储在映射中时触发事件(emit
events)。在ERC20代币合约中,你可以通过追踪代币的Transfer事件的地址来获取代币持有者列表。这个过程很难。对此,我们准备了两个帮助方案:第一,你可以扫描区块链并自行检索持有者;第二,你可以依靠以太坊区块链的公开GoogBigTable存档。如果你不熟悉web3
API,无法从区块链中提取信息。那么你可以使用ethereum-etl
[5],其提供了一系列脚本来简化数据提取的过程。如果你没有已经完成同步的区块链,那么你可以使用Google
BigQuery
API。图1展示了如何通过BigQuery来收集某个特定代币的所有地址:图1:利用Google
BigQuery来恢复那些与在0x41424344这个地址中的代币相关联的Transfer事件的所有地址BigQuery提供对区块号的访问,因此你可以将查询结果调整为返回特定区块的交易。一旦你恢复了所有代币持有者的地址,你就可以离线查询balanceOf函数
[6]
以恢复与每个持有者相关的余额,同时过滤余额为零的帐户。现在我们知道如何检索将要迁移的数据,接下来我们要将数据写入新合约。第二步:数据写入完成数据收集后,你需要开启新合约。对于简单变量,你可以通过合约的构造函数来设置相应的值。如果你的数据无法保存在单笔交易中,那么情况会有点复杂,成本也会略高。每笔交易都包含在某个区块中,该区块限制了其交易可以使用的gas总量(即所谓的GasLimit)。如果某笔交易的gas
成本接近或超过此限制,那么矿工将不会将其打包进该区块内。因此,如果想要迁移大量数据,那么你必须将数据迁移拆分成多笔交易。这类情况的解决方案是:在合约中添加初始化状态,只有合约拥有者才能更改状态变量,并且用户无法执行任何操作。对于ERC20代币,上述过程将需要以下步骤:在初始化状态下部署合约,迁移余额,将合约的状态移至生产状态。初始化状态可以通过使用OpenZeppelin提供的Pausable功能
[7]
和指示初始化状态的布尔值(boolean)来实现。为了降低成本,我们可以使用batchTransfer(批量传输)函数(该函数允许你在单笔交易中设置多个帐户)来实现余额的迁移:图2:batchTransfer函数示例关于迁移的担忧在迁移合约时,会出现两个主要问题:1.
需要花费多少迁移成本?2.
对交易所有什么影响?迁移成本数据恢复是在在链下完成的,因此是免费的;Ethereum-etl
[8]也可以在本地使用;谷歌的BigQuery API [9]
提供足够的免费额度来支付其使用费用。但是,发送到网络中的每一笔交易和新合约存储的每个字节都需要花费成本。使用图2的batchTransfer函数,给200个账户转账的成本约为2.4M
gas ,依照本文撰写时的平均gas 价格(10
Gwei)约为5.04美元(你也可以使用ETH Gas Station [10]
重新计算最新的数值)。粗略计算,每迁移一个余额需要花费0.025美元。如果我们看看按市值排名的前五大ERC20代币
[11] 的持有人数,我们可以得到:如果你想迁移其它信息(例如allowance
[12]
功能),那么成本会更高。即便如此,与这些代币所拥有的金额以及升级失败的潜在成本相比,所需的成本费用依旧很低。交易所部署新合约可能会产生一些操作后果。对于基于代币的合约,其运营团队在迁移期间与交易所的协作非常重要,他们需要确保新合约被上线,同时旧合约将被废弃。幸运的是,先前的代币迁移事件(例如Augur
[13],Vechain [14]和Tron
[15])表明:交易所基本都会合作。合约迁移v.s.
可升级合约在之前的博文[16]中,我们讨论了智能合约设计的趋势:即在合约内增加可升级机制。可升级合约有几个缺点:需要掌握详细的EVM和Solidity底层专业知识。基于delegatecall的代理要求开发者掌握EVM和Solidity内部学识。提高了复杂性和代码量。合约更难进行审查,更有可能包含漏洞和安全问题。增加了需要掌握的密钥数量。合约将需要多个授权用户(拥有者,升级者)。授权用户越多,攻击面越大。提高了每笔交易的gas成本。相对于同一版本但没有升级机制的合约,有升级机制的合约的竞争力下降。可升级合约鼓励在合约部署后再解决问题。如果开发人员知道无法轻松地更新合约,他们往往会更彻底地对合约进行测试和审查。可升级合约减少了用户对合约的信任。用户需要信任合约的拥有者,但这会阻碍真正的去中心系统的发展。只有在存在强有力的论据时,合约才应具有可升级机制,例如:合约需要经常更新。如果合约需要定期修改,那么定期迁移的成本将会非常高,相比之下,可升级机制反而更加合理。合约需要一个固定的地址。合约的迁移需要使用新的地址,这可能会破坏与第三方的交互(例如与其它合约的交互)。合约迁移在实现升级所带来的优点的同时,还避免了不少缺点。升级相对于迁移的主要优点是:升级的成本更低。然而,这种成本并不足以覆盖其所有的缺点。建议在合约部署之前做好迁移程序的功课。使用事件(events)来提高数据追踪的效率。如果你想要部署可升级合约,那么你必须准备好迁移程序,因为你的密钥可能会受到损害,或者你的合约可能会受到错误且不可逆转的操纵。智能合约带来了新的开发范式——其不可变性要求用户重新思考搭建应用的方式,并且需要更透彻全面的设计和开发过程。正文中涉及的链接:[1]:
of Bits
Blog翻译:喏呗尔原文链接:

这个是基本的智能合约的需求方案:• 建材尤其是大宗交易,订货,交割问题。•
智能合约,解决卖家信用“假一赔十”,基于智能合约,自动进行赔付。用户无法真正信任建材供应商的广告。
基于触发的赔付条件,解决主管判断赔付标准的问题。因为区块链智能合约不能修改的特性,赔付过程将通过锁定在智能合约上的STO代币执行,从而保障了承诺的赔付必定会得到履行。•
建材二次使用转移问题○ 共享经济:剩余建材共享,线上商城二次销售。•
建材溯源• 建材商城

结论

这部分帮助我们构建了一个基本代币,我们将在The Neverending Story中将其用作参与/共享代币。虽然代币具有效用,但它的定义是作为一种资产来控制更大的体量的安全代币。注意区别。

在本系列的下一部分中,我们将学习如何编译,部署和测试此代币。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文以太坊构建DApps系列教程:构建TNS代币

完整代码:

pragma solidity ^0.4.24;import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol";contract TNStoken is Ownable { using SafeMath for uint256; mapping(address => uint256) balances; mapping(address => uint256) locked; mapping (address => mapping (address => uint256)) internal allowed; uint256 totalSupply_; event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); event Locked(address indexed owner, uint256 indexed amount); string public name; string public symbol; uint8 public decimals; constructor() public { name = "The Neverending Story Token"; symbol = "TNS"; decimals = 18; totalSupply_ = 100 * 10**6 * 10**18; balances[msg.sender] = totalSupply_; } /** @dev _owner will be prevented from sending _amount of tokens. Anythingbeyond this amount will be spendable. */ function increaseLockedAmount(address _owner, uint256 _amount) public onlyOwner returns  { uint256 lockingAmount = locked[_owner].add; require(balanceOf >= lockingAmount, "Locking amount must not exceed balance"); locked[_owner] = lockingAmount; emit Locked(_owner, lockingAmount); return lockingAmount; } /** @dev _owner will be allowed to send _amount of tokens again. Anythingremaining locked will still not be spendable. If the _amount is greaterthan the locked amount, the locked amount is zeroed out. Cannot be neg. */ function decreaseLockedAmount(address _owner, uint256 _amount) public onlyOwner returns  { uint256 amt = _amount; require(locked[_owner] > 0, "Cannot go negative. Already at 0 locked tokens."); if (amt > locked[_owner]) { amt = locked[_owner]; } uint256 lockingAmount = locked[_owner].sub; locked[_owner] = lockingAmount; emit Locked(_owner, lockingAmount); return lockingAmount; } function transfer(address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[msg.sender] - locked[msg.sender]); balances[msg.sender] = balances[msg.sender].sub; balances[_to] = balances[_to].add; emit Transfer(msg.sender, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns  { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[_from] - locked[_from]); require(_value <= allowed[_from][msg.sender] - locked[_from]); balances[_from] = balances[_from].sub; balances[_to] = balances[_to].add; allowed[_from][msg.sender] = allowed[_from][msg.sender].sub; emit Transfer(_from, _to, _value); return true; } function increaseApproval(address _spender, uint _addedValue) public returns  { allowed[msg.sender][_spender] = ( allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } function decreaseApproval(address _spender, uint _subtractedValue) public returns  { uint oldValue = allowed[msg.sender][_spender]; if (_subtractedValue > oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } /** @dev Returns number of tokens the address is still prevented from using */ function getLockedAmount(address _owner) public view returns  { return locked[_owner]; } /** @dev Returns number of tokens the address is allowed to send */ function getUnlockedAmount(address _owner) public view returns  { return balances[_owner].sub(locked[_owner]); } function balanceOf(address _owner) public view returns  { return balances[_owner]; } function totalSupply() public view returns  { return totalSupply_; } function allowance(address _owner, address _spender) public view returns  { return allowed[_owner][_spender]; }}

创建迁移

对于每个合约,我们需要告诉Truffle哪个合约是我们想要部署的合约以及我们可以在哪里找到合约。这是通过/Truffle/migrations文件夹中的迁移文件完成的。

迁移脚本02_deploy_token.js应如下所示

var CoinFabrikToken = artifacts.require("./CoinFabrikToken.sol");module.exports = function { deployer.deploy(CoinFabrikToken);};

我们已配置Truffle,我们的节点已同步,我们的合约已经编写并且我们的迁移已配置,完成部署就是个时间问题。

二、开发环境搭建windows下开发环境:• Geth 工具 • Node.js
(javascript运行环境)○ 安装后,提供 truffle、npm 运行环境○ 框架-Truffle

在本系列关于使用以太坊构建DApps教程的第1部分中,我们引导大家做了两个版本的本地区块链进行开发:一个Ganache版本和一个完整的私有PoA版本。

结论

在演练的第二部分中,我展示了在RSK网络中开发简单智能合约的示例。
我们已经看过:

  • 从OpenZeppelin套件导入库和合约,
  • 使用这些库创建一个简单的代币,
  • 配置Truffle的迁移过程,
  • 将我们的合约部署到RSK主网络,
  • 通过不同的账户与合约互动,
  • 检查块的日志以获取有关事务的反馈。

正如我们所看到的,RSK网络用于Solidity Smart
Contracts部署和交互的用法几乎与以太坊节点中的相同。当然,这仍然是一个测试网络,预计会出现问题和错误,主要是在节点中,但RSK
Labs团队在他们出现时尽可能快地解决它们。随着时间的推移,将实现稳健性。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是原文使用OpenZeppelin在RSK上进行ERC20代币开发

toWei 代表把1个eth以太币,转换成 wei 单位,1eth=10 ** 18 wei;

基本依赖

为了开发我们的应用程序,我们可以使用几种框架和入门开发包中的一种:Dapp,eth-utils,Populus,Embark……等等。但我们会选择现在的生态系统之王Truffle。

使用以下命令安装它:

npm install -g truffle 

这将使truffle命令无处不在。现在我们可以用truffle init启动项目。

部署

如果我们之前停止了我们的节点,我们将恢复在线状态,然后我们将与Truffle连接:

$ sudo service rsk start$ cd ~/Truffle/ && truffle console --network rsk

之后编译合约:

truffle> compile --all

不应该对我们的合约有任何错误或警告。然后我们转移合约:

truffle> migrate --reset

为了节约时间,我们可以在一行中执行两个命令

truffle> migrate --all --reset

将首先部署迁移合约。Truffle为我们提供了每个操作的交易哈希,因此我们可以稍后检查详细信息或日志。这是我收到的完整输出

truffle> migrate --all --resetCompiling ./contracts/CoinFabrikToken.sol...Compiling ./contracts/Migrations.sol...Compiling zeppelin-solidity/contracts/math/SafeMath.sol...Compiling zeppelin-solidity/contracts/ownership/Ownable.sol...Compiling zeppelin-solidity/contracts/token/ERC20/BasicToken.sol...Compiling zeppelin-solidity/contracts/token/ERC20/ERC20.sol...Compiling zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol...Compiling zeppelin-solidity/contracts/token/ERC20/StandardToken.sol...Writing artifacts to ./build/contracts Using network 'rsk'. Running migration: 1_initial_migration.js Deploying Migrations... ... 0xf00d4ecf2b5752022384f7609fe991aa72dda00a0167a974e8c69864844ae270 Migrations: 0x1dc2550023bc8858a7e5521292356a3d42cdcbe9Saving successful migration to network... ... 0x3e759e8ff8a7b8e47a441481fa5573ccf502b83f3d591ad3047e622af0f9169eSaving artifacts...Running migration: 2_deploy_token.js Deploying CoinFabrikToken... ... 0x300c8bb1e434e2aa4b13dcc76087d42fcbe0cb953989ca53a336c59298716433 CoinFabrikToken: 0xc341678c01bcffa4f7362b2fceb23fbfd33373eaSaving successful migration to network... ... 0x71771f7ee5d4e251e386979122bdda8728fa519d95a054572751bb10d40eb8c5Saving artifacts...

如果我们检查交易,我们可以计算所有部署过程的gas成本。在我这里的情况,它是2340788gas(277462+42008+1994310+27008)。

因此将其更改为真实的SBTC,我们得到2340788*183000000/10^18=0,000428364
SBTC。在撰写本文时,这大约是4美元左右。

我们的合约现在部署在0xc341678c01bcffa4f7362b2fceb23fbfd33373ea。

恭喜!

• 常用以太坊交互代码库• Web3.js – 以太坊官方的 Java API• Eth.js –
优化过的 Web3.js

构造函数

到目前为止,我们只是建立了一个代币“合约”。但是这个标记是什么?它叫什么?它有多少位小数?我们如何使用它?

在一开始,我们定义了一个constructor函数。现在,让我们完成它的主体并添加属性namesymboldecimals

string public name;string public symbol;uint8 public decimals;constructor(string _name, string _symbol, uint8 _decimals, uint256 _totalSupply) public { name = _name; symbol = _symbol; decimals = _decimals; totalSupply_ = _totalSupply;}

这样做可以让我们稍后重复使用同一类型的其他代币。但是,当我们确切知道我们正在构建的内容时,让我们对这些值进行硬编码:

string public name;string public symbol;uint8 public decimals;constructor() public { name = "The Neverending Story Token; symbol = "TNS"; decimals = 18; totalSupply_ = 100 * 10**6 * 10**18;}

显示代币信息时,各种以太坊工具和平台会读取这些详细信息。将合约部署到以太坊网络时会自动调用构造函数,因此这些值将在部署时自动配置。

关于totalSupply_ = 100*10**6*10**18,这句话只是让人们更容易阅读数字的一种方式。由于以太坊中的所有发送都是使用最小的以太单位或代币完成的,因此最小单位是小数点后18位小数。这就是说单个TNS代币为1*10**18*。此外,我们想要1亿,所以100*10**6100*10*10*10*10*10*10。这使得数字比100000000000000000000000000更易读。

所有权控制

我们将首先使用我们讨论过的库来测试合约的所有权功能。

如果我们从任何帐户调用getON函数,只要它是公开的并且没有任何所有权问题,我们就会得到:

truffle> cfToken.getON()''

现在,setON函数具有所有权属性。任何来自其他帐户的交易都将被驳回。例如,我们看到,试图用我的名字从acc1签订合约不会改变它的价值。

truffle> cfToken.setON('Andres Bachfischer', {from: acc1})0x5f115190b60238240bedf36d1c5bb69a443a0f8ee971b0fc40fe5ca9c727d47c

威尼斯app 1image

使用交易的哈希,我们看到返回的值为false,并且函数未正确执行。再次调用getON函数,我们看到变量没有改变它的值。

现在签署相同的交易但是从所有者的帐户acc0,我们得到状态’0x01’并且该功能正确执行。

truffle> cfToken.setON('Andres Bachfischer', {from: acc0})0x0c894fa7e5369573fb14addeaed4cd9d5b6cd1425cb4eeeae16cb4e1fa8e0364

威尼斯app 2image

再次调用函数getON,我们看到所有权库按照我们希望的那样工作。

truffle> cfToken.getON()

威尼斯app 3image

Ownable.sol还具有允许我们将合约所有者更改为其他地址的功能。我们不会用它。然而,它的用法如下:

truffle> cfToken.transferOwnership(acc1, {from: acc0}) 

有了这个,acc1将成为合约的新所有者。

让我们转到代币。

五、如何进行合约初始化这个初始化,指的是合约部署到区块链上后,代币名称、总发行量
等一般分两种,无参初始化和带参初始化

总供应量

知道代币的总供应量对于其用户和代币跟踪应用程序非常重要,所以让我们定义一个合约属性来跟踪这个和另一个自由函数来读取它:

uint256 totalSupply_;function totalSupply() public view returns  { return totalSupply_;}

在本文中,我们将讨论通过RSK网络部署和交互Smart-Contracts智能合约。我们的合约将是一个基于OpenZeppelin库的ERC20代币,我们将把它直接部署到Mainnet中。

七、发布后获得 合约地址、ABI 等参数,在前端进行调用合约交互

替代开发方案

或者,我们也可以扩展Zeppelin合约,修改一些属性,然后我们就拥有代币了。这就是大多数人所做的,但在处理可能数百万其他人的钱的软件时,我个人倾向于想知道我在代码中的确切内容,因此盲目代码重用在我的个人情况下是要最小化的。

pragma solidity ^0.4.24;import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";import "../node_modules/openzeppelin-solidity/contracts/token/ERC827/ERC20Token.sol";contract TNStoken is ERC20Token { using SafeMath for uint256; string public name; string public symbol; uint8 public decimals; uint256 totalSupply_; constructor() public { name = "The Neverending Story Token"; symbol = "TNS"; decimals = 18; totalSupply_ = 100 * 10**6 * 10**18; }}

在这种情况下,我们使用is符号来声明我们的代币是ERC20Token。这使得我们的代币扩展了ERC20合约,后者又扩展了StandardToken,等等……

无论哪种方式,我们的代币现在已准备就绪。但谁得到了多少代币以及如何开始?

创建合约

我们需要做的第一件事就是知道如何使用Truffle

当我们这样做

$ truffle init

在一个空文件夹中,除了创建配置文件外,我们还为项目和迁移合约创建了文件夹,以记录对同一合约的更改。

合约的.sol代码文件位于

~/Truffle/contracts

迁移脚本在

~/Truffle/migrations

已编译的合约在

~/Truffle/build

测试合约在

~/Truffle/test

我们现在只处理前两个文件夹。

在Truffle文件夹中,我们从OpenZeppelin导入库

$ npm install -E openzeppelin-solidity

这些库不仅会安装我们代币token的主要类库,还会安装所有权相关,安全数学运算和许多其他设施的库。值得一提的是,这些库已经过审核以实现高标准的安全性,因此依赖于它们的合约在正确使用时不易受到黑客攻击。

我们的库将安装在

~/Truffle/node_modules/openzeppelin-solidity/contracts

之后,我们可以将库ABCD.sol导入到我们的合约中,如下所示:

import 'zeppelin-solidity/contracts/token/ERC20/ABCD.sol';

要创建我们的ERC20代币,我们将从该存储库导入2个库:StandardToken.sol,它具有代币的主要功能,并且已经更多地导入了一堆库,例如SafeMath.solOwnable.sol,这些允许我们设置所有者对合约中的功能控制。

要继承库属性和函数,我们只需使用“is”关键字以这种方式将合约定义为StandardTokenOwnable

contract CoinFabrikToken is StandardToken, Ownable { }

之后,我们拥有这些库和导入库中的所有功能。

接下来,我们将代币的名称定义为CoinFabrik,这是它的符号,18个小数位,用于代币的精度(以太坊类网络中的标准,使我们有可能使用web3的以太转换功能)并将代币的初始供应量设置为1000,像这样:

string public name = 'CoinFabrik';string public symbol = 'CF';uint8 public decimals = 18;uint public INITIAL_SUPPLY = 1000;

我们还将创建另一个字符串,一个与代币功能无关的非公共变量,以显示Ownable库属性的用法,该属性仅允许创建者与某些指定的函数进行交互。我们稍后会看到。

已经定义了我们的参数,现在是时候通过构造函数将它们分配给Token变量了。到目前为止,构造函数被定义为一个与智能合约同名的函数,但是从现在开始,将会有一个名为constructor()的函数,它将替换旧方法。如果你像以前一样调用构造函数,Solidity编译器将发出警告。

INITIAL_SUPPLY乘以小数精度的次方将分配给BasicToken合约的totalSupply_

totalSupply_ = INITIAL_SUPPLY * (10**uint);

并将它们存入创作者的帐户:

balancesb [msg.sender] = totalSupply_;

有了这个,我们就可以使用一个简单而标准的代币,但正如我们所说,我们将使用Ownable合约添加一些功能。首先,我们将定义一些函数:一个修改我们的非公共变量的状态,但只有你拥有权限,而另一个函数返回字符串的消息。定义如下:

function setON(string _n) public onlyOwner returns  { Owner = _n; return true; } function getON() public view returns  { return Owner; }

两者都是公开的,所以任何人都可以尝试调用他们,但对于第一个,只有所有者的地址不会导致恢复。如果你是所有者并且调用了函数,则字符串将保存在我们的变量Owner中,并且它还将返回一个我们可以在交易中检查的true值。

由于Owner变量不是公共的并且没有Getter,我们需要一个函数来返回变量的值而不改变区块链的状态。这是第二个功能。

我们还将创建一个回调函数,如果有人错误地调用我们的合约,则会发出事件:

function () public payable { if (msg.value > 0) { emit Yes('Thanks for donating SBTC! :)'); } else { emit No('Error 404: Function not found :P'); }}

最后,我们在合约中添加了一个可销毁的功能,其中所有者是唯一可以执行它的人。

我们的简单代币已经完成。所有代码应该是一样的:

pragma solidity ^0.4.17; import 'zeppelin-solidity/contracts/token/ERC20/StandardToken.sol';import "zeppelin-solidity/contracts/ownership/Ownable.sol"; contract CoinFabrikToken is StandardToken, Ownable { string public name = 'CoinFabrik'; string public symbol = 'CF'; uint8 public decimals = 18; uint public INITIAL_SUPPLY = 1000; string Owner; event Yes; event No; constructor() public { totalSupply_ = INITIAL_SUPPLY * (10**uint); balances[msg.sender] = totalSupply_; } function setON(string _n) public onlyOwner returns  { Owner = _n; return true; } function getON() public view returns  { return Owner; } function () public payable { if (msg.value > 0) { emit Yes('Thanks for donating SBTC! :)'); } else { emit No('Error 404: Function not found :P'); } } function destroy() public onlyOwner { selfdestruct; } }

我们前面说到过,测试链
执行合约,是需要消耗gas的,测试链服务端开启挖矿模式,就会慢慢获得gas,那么其它账户如何也能获得gas,进行相关业务操作?通过命令,从0号账户给
1号账户 ,转1个ethEth.sendTransaction({from:eth.acounts[0],
to:eth.accounts[1], value:web3.toWei(1,”ether”) });

SafeMath

我们将在这种情况下使用的唯一Zeppelin合约是他们的SafeMath合约。在Solidity中,我们使用import关键字导入合约,而编译器通常不需要完整路径,只需要相对的路径,如下所示:

pragma solidity ^0.4.24;import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";contract TNStoken { using SafeMath for uint256; constructor() public { }}

那么,什么是SafeMath?很久以前,由于代码中的数学问题,出现了1840亿比特币的问题。为了防止类似于这些问题(并非特别只在以太坊中可能存在这一问题),SafeMath库仍然存在。当两个数字具有MAX_INT大小(即操作系统中的最大可能数量)时,将它们相加会使值wrap around重新归零,就像汽车的里程表在达到999999公里后重置为0。所以SafeMath库具有以下功能:

/*** @dev Adds two numbers, throws on overflow.*/function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; assert(c >= a); return c;}

此函数可以防止此问题:它检查两个数字的总和是否仍然大于两个操作数中的每一个。

虽然在撰写Solidity合约时犯下如此愚蠢的错误并不容易,但保持安全比抱歉更好。

通过using SafeMath for uint256,我们用这些“安全”版本替换Solidity(256bit
unsigned – aka positive-only – whole
numbers)中的标准uint256数字。而不是像这样求和数:sum=someBigNumber+someBiggerNumber,我们将这样求和:sum=someBigNumber.add(someBiggerNumber),从而在我们的计算中是安全的。

与合约互动

通过Truffle迁移给出的地址,以及合约的ABI,我们创建了一个实例,因此简化语法更容易处理函数。为此,在我们部署之后,我们写了

truffle> var cfToken = web3.eth.contract(CoinFabrikToken.abi).at(CoinFabrikToken.address)

如果合约已经部署,并且知道它的地址和ABI,我们就可以做到

truffle> var cfToken = web3.eth.contract(‘Contract_ABI’).at(‘Contract_ADDRESS’)

其中Contract_ABI是简化为一行ABI,Contract_ADDRESS不需要解释。

我之前创建了2个帐户,现在为方便起见,我们将它们重命名:

truffle> var acc0 = web3.eth.accounts[0]truffle> var acc1 = web3.eth.accounts[1]

acc0是部署合约的人。Acc0被添加到truffle.jsnode.conf配置文件中。

如果熟悉C#类中有 构造函数,在这个类初始化时,该构造函数
就自动执行了。那在智能合约中,当合约部署到区块链上的时候,该构造的业务就执行了,不需要显示的去调用。•
要在以太坊上进行操作,必需要有以太坊账户。

先决条件

按照上一部分,启动并运行Ganache版本。或者,如果你没有从第一部分开始跟踪,则可以运行任何本地版本的区块链,但请确保你可以使用我们需要的工具连接到它。

我们假设你有一个有效的私有区块链,能够通过终端应用程序在其控制台和操作系统终端中输入命令,或者在Windows上,通过Git
Bash,Console,CMD Prompt,Powershell等应用程序输入命令。

代币操作

我们要做的第一件事是检查在创建合约时是否正确分配了代币的余额。

我们检查每个帐户的余额如下:

web3.fromWei(cfToken.balanceOf.toString // = ‘1000’web3.fromWei(cfToken.balanceOf.toString // = ‘0’

因此,我们可以看到所有代币都已正确分配到我们的初始帐户。

我们要做的第一笔交易是将一些代币转移到第二个帐户acc1威尼斯app,,进行三次。

为第一笔交易这样做:

truffle> cfToken.transfer(acc1, web3.toWei, {from: acc0})0xd45437b777f1430e7cec57bd80b261ce8f87bf8a3f9a113fecd20563403c4d9c

威尼斯app 4image

truffle> web3.fromWei(cfToken.balanceOf.toString // = '733.6'truffle> web3.fromWei(cfToken.balanceOf.toString // = '266.4'

威尼斯app 5image

我们看到从我们的部署帐户中获取的代币与在acc1中收到的代币数量相同。

使用StandardToken合约,我们还获得了代表某个帐户(在本例中为acc1)支出代币的权限。如果我们想在获得批准之前执行此操作,则交易将失败(状态为“0x00”)

truffle> cfToken.transferFrom(acc1, acc0, web3.toWei, {from: acc0})0x5cee7cf60849283a0088d71483a606ba2101b500e13f972abada4f75781596bf

威尼斯app 6image

检查后,acc0不允许从acc1发送:

truffle> web3.fromWei(cfToken.allowance(acc1, acc0, {from: acc0}).toString // = '0'

我们授权acc0acc1的交易中以acc1的名义花费10个代币:

truffle> cfToken.approve(acc0, web3.toWei, {from: acc1})0x6e1a202f4ca7f43dfb28034952d54a572993b986a55857790aa51854afbc1fb4

威尼斯app 7image

在输出日志中,我们看到函数已成功完成,并且日志显示允许acc0用于支出的金额。检查allowance:

truffle> web3.fromWei(cfToken.allowance(acc1, acc0, {from: acc0}).toString // = '10'

威尼斯app 8image

现在,如果我们再次执行支出交易:

truffle> cfToken.transferFrom(acc1, acc0, web3.toWei, {from: acc0})0x41f750eabb6e0d3ab576aac0333b0d337ca61808aae1eeafa9d8e2a0b81b979b

我们得到状态为“0x01”的成功交易。

威尼斯app 9image

再检查一下余额:

truffle> web3.fromWei(cfToken.balanceOf.toString // = '738.6'truffle> web3.fromWei(cfToken.balanceOf.toString // = '261.4'

威尼斯app 10image

最后,如果我们签署一个调用不可用函数的事务,我们将调用我们的回退函数。
签署一个像这样的交易:

truffle> web3.eth.sendTransaction({from: acc0, to: cfToken.address})0x4106a287fc60669bf9682a73ec4c457b094c086ec7408a5dea95d200688c4ee9

威尼斯app 11image

将返回一个日志,其数据表示字符串Error 404:Function not found:P(十六进制:'0x00 ... 00204572726f72203430343a2046756e6374696f6e206e6f7420666f756e64203a50')。

我们的最后一个功能,即我们不会因为显而易见的原因而执行,就是销毁功能。我们需要合约不被销毁才能显示交易。要调用,所有者应该这样做:

truffle> cfToken.destroy({from: acc0})

使用测试或者调试器与合约进行交互非常好,或者你也可以手动执行交易。
Truffle 提供了两种简单的方式与合约交互。• 入口:在vscode菜单中打开,点击
“集成终端”• Truffle console
一个可以和任何以太坊客户端交互的交互式控制台。• Truffle Develop
一个提供了本地私有开发链的交互式控制台。

津贴

有时可能会允许第三方退出其他帐户的余额。这对于可能促进游戏内购买,去中心化交易等的游戏应用非常有用。我们通过构建一个名为allowance的多维mapping实现这一点,该mapping存储了所有这些权限。我们添加以下内容:

mapping (address => mapping (address => uint256)) internal allowed;event Approval(address indexed owner, address indexed spender, uint256 value);

这个事件就在那里,以便应用程序可以知道有人预先批准了其他人的余额支出,一个有用的功能,以及标准的一部分。

映射将地址与另一个映射相结合,该映射将地址与数字组合在一起,它基本上形成了一个像这样的电子表格:

威尼斯app 12image

所以Bob的余额可能由Mary支付,最多可达1000个代币,Billy最多可达50个代币。Bob可以将Mary的余额花费750代币。Billy的余额最多可以由Mary花费300个,而Joe花费1500。

鉴于此映射是internal映射,它只能由此合约中的函数和使用此合约作为基础的合约使用。

要批准其他人从你的帐户中扣款,你可以使用允许使用代币的人的地址,允许他们支付的金额以及你发出Approval事件的功能来调用approve功能:

function approve(address _spender, uint256 _value) public returns  { allowed[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true;}

我们还需要一种方法来读取用户可以从其他用户的帐户中花费多少:

function allowance(address _owner, address _spender) public view returns  { return allowed[_owner][_spender];}

所以它是另一个read only函数(view),这意味着它可以自由执行。它只是读取剩余的可提取余额。

那么如何为别人发送?使用新的transferFrom功能:

function transferFrom(address _from, address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[_from]); require(_value <= allowed[_from][msg.sender]); balances[_from] = balances[_from].sub; balances[_to] = balances[_to].add; allowed[_from][msg.sender] = allowed[_from][msg.sender].sub; emit Transfer(_from, _to, _value); return true;}

和以前一样,有健全性检查:目标地址不能是空地址,因此不要将代币发送到不存在的地方。发送的值还需要不仅小于或等于发送值当前帐户的余额,而且还需要小于或等于消息发送者仍然允许为他们花费的余额。

接下来,更新余额并使允许的余额与发出有关发送事件之前的余额同步。

注意:代币持有者可以在不更新allowed映射的情况下allowed代币。如果代币持有者使用transfer手动发送代币,则会发生这种情况。在这种情况下,持有人的代币可能比第三方可以支付的额外费用少。

通过批准和许可,我们还可以创建让代币持有者增加或减少某人津贴的功能,而不是完全覆盖该值。尝试将此作为练习,然后参考下面的源代码以获得解决方案。

function increaseApproval(address _spender, uint _addedValue) public returns  { allowed[msg.sender][_spender] = ( allowed[msg.sender][_spender].add(_addedValue)); emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true;}function decreaseApproval(address _spender, uint _subtractedValue) public returns  { uint oldValue = allowed[msg.sender][_spender]; if (_subtractedValue > oldValue) { allowed[msg.sender][_spender] = 0; } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true;}

测试工具及环境:• Ganache• Etherum-Wallet 以太坊钱包• MateMask• Remix○
集成开发环境-Remix –
一个基于solidity语言的在线智能合约开发IDE,它提供从编译,调试到部署的全流程支持。•
EtherScan○ 浏览器-Etherscan –
最为流行的以太坊浏览器,用于查看交易信息和合约代码• gas
计算-EthGasStation – 估计交易费用和时间的网站

代币锁定

看到我们打算使用代币作为投票权(即你在投票期间锁定了多少代币代表你的投票有多强大),我们需要一种方法来防止用户在投票后发送它们,否则我们的DAO将容易受到Sybil攻击的影响——拥有一百万个代币的个人可以注册100个地址,并通过将它们发送到不同的地址并使用新地址重新投票来获得1亿个代币的投票权。因此,我们将阻止发送与一个人投票额完全一样多的代币,对每个提案的每次投票都是累积的。这是我们在本文开头提到的扭曲。让我们在合约中添加以下事件:

event Locked(address indexed owner, uint256 indexed amount);

然后让我们添加锁定方法:

function increaseLockedAmount(address _owner, uint256 _amount) onlyOwner public returns  { uint256 lockingAmount = locked[_owner].add; require(balanceOf >= lockingAmount, "Locking amount must not exceed balance"); locked[_owner] = lockingAmount; emit Locked(_owner, lockingAmount); return lockingAmount;}function decreaseLockedAmount(address _owner, uint256 _amount) onlyOwner public returns  { uint256 amt = _amount; require(locked[_owner] > 0, "Cannot go negative. Already at 0 locked tokens."); if (amt > locked[_owner]) { amt = locked[_owner]; } uint256 lockingAmount = locked[_owner].sub; locked[_owner] = lockingAmount; emit Locked(_owner, lockingAmount); return lockingAmount;}

每种方法都确保不会锁定或解锁非法金额,然后在更改给定地址的锁定金额后发出事件。每个函数还返回现在为此用户锁定的新金额。但这仍然不能阻止发送。让我们修改transfertransferFrom

function transfer(address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[msg.sender] - locked[msg.sender]); // <-- THIS LINE IS DIFFERENT // ...function transferFrom(address _from, address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[_from] - locked[_from]); require(_value <= allowed[_from][msg.sender] - locked[_from]); // <-- THIS LINE IS DIFFERENT // ...

最后,我们需要知道为用户锁定或解锁了多少代币:

function getLockedAmount(address _owner) view public returns  { return locked[_owner];}function getUnlockedAmount(address _owner) view public returns  { return balances[_owner].sub(locked[_owner]);}

就是这样:我们的代币现在可以从外部锁定,但只能由代币合约的所有者锁定(这将是我们将在即将到来的教程中构建的Story
DAO)。让我们将代币合约设为Ownable,即允许它拥有一个所有者。使用import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol"导入;然后更改此行:

 contract StoryDao { 

……是这样的:

 contract StoryDao is Ownable { 

八、在以太坊Ropsten浏览器上,查询交易记录

发送代币

接下来,让我们确保一些代币的所有者可以将它们发送给其他人。我们还想知道发送何时发生,因此我们也将定义发送事件。Transfer事件允许我们通过JavaScript监听区块链中的传输,以便我们的应用程序可以知道何时发出这些事件,而不是不断地手动检查传输是否发生。事件与合约中的变量一起声明,并使用emit关键字发出。我们现在将以下内容添加到合约中:

event Transfer(address indexed from, address indexed to, uint256 value);function transfer(address _to, uint256 _value) public returns  { require(_to != address; require(_value <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender].sub; balances[_to] = balances[_to].add; emit Transfer(msg.sender, _to, _value); return true;}

此函数接受两个参数:_to,它是将接收代币的目标地址,以及value,即代币的数量。重要的是要记住,value是代币的最小单位数,而不是整个单位。因此,如果一个代币被声明具有10位小数的话,那么为了发送一个代币,你将发送10000000000。这种粒度级别允许我们处理极小数量。

该函数是公共的,这意味着任何人都可以使用它,包括其他合约和用户,并且如果操作成功则返回true

然后该功能进行一些健全性检查。首先,它检查目标地址是否为空地址。换句话说,不得将代币必须正常发送。接下来,它通过比较它们的余额(balances[msg.sender])和传入的发送值来检查发件人是否甚至被允许发送这么多代币。如果这些检查中的任何一个失败,该函数将拒绝该交易并失败。它将退还所发送的任何代币,但是在此之前用于执行该功能的gas将被花费。

接下来的两行从发件人的余额中减去代币数量,并将该金额添加到目的地余额中。然后使用emit事件,并传入一些值:发件人,收件人和金额。现在,任何订阅了此合约上的发送事件的客户都将收到此事件的通知。

好的,现在我们的代币持有者可以发送代币。信不信由你,这就是基本代币所需要的一切。但我们已经要超越了这一点,并增加了一些功能。

三种方式与区块链交互• Javascript control geth控制台• Json-rpc
无状态远程调用协议• Web3.js 以太坊提供的javascript库

完整代码

此时带有自定义函数注释的代币的完整代码见文末所示。

四、合约执行过程• Truffle compile
智能合约进行编译,生成字节码,成功后会在项目目录中生成一个build的目录○
重新编译所有的代码 truffle compile –all• Truffile migrate 合约部署,○
重新部署合约 truffle migrate –reset

来自Scratch的ERC20

我们的数学计算安全了,我们可以创建我们的代币。

ERC20是一个定义明确的标准,所以作为参考,我们将它添加到合约中。在这里阅读代币标准

所以ERC20代币应该具有的功能是:

pragma solidity ^0.4.24;import "../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";contract ERC20 { function totalSupply() public view returns ; function balanceOf(address who) public view returns ; function transfer(address to, uint256 value) public returns ; event Transfer(address indexed from, address indexed to, uint256 value); function allowance(address owner, address spender) public view returns ; function transferFrom(address from, address to, uint256 value) public returns ; function approve(address spender, uint256 value) public returns ; event Approval(address indexed owner, address indexed spender, uint256 value);}contract TNStoken { using SafeMath for uint256; constructor() public { }}

这可能看起来很复杂,但实际上非常简单。这是我们代币需要具有的函数的“目录”,我们将逐个构建它们,解释每个函数的含义。考虑上面的代币接口。在创建Story
DAO应用程序时,我们将看到它如何以及为何有用。

最近刚交付的一个区块链项目。

在这一部分中,我们将深入研究并构建我们的TNS代币:用户将使用代币对Story
DAO中的提案进行投票。

如果要把智能合约的安全等级 升一级,强烈推荐基于 OpenZeppelin
进行重构,前提是业务一定要清OpenZeppelin ,简书和
git上可自行查阅openzeppelin-solidity,安全合约库

基本余额

开始吧。代币实际上只是以太坊区块链中的“电子表格”,如下所示:

Name Amount
Bruno 4000
Joe 5000
Anne 0
Mike 300

所以让我们创建一个mapping,它基本上就像合约中的电子表格:

mapping(address => uint256) balances; 

根据上面的接口,这需要伴随一个balanceOf函数,它可以读取此表:

function balanceOf(address _owner) public view returns  { return balances[_owner];}

函数balanceOf接受一个参数:_ownerpublic,是一个view函数(意思是它可以自由使用——不需要交易),并返回一个uint256编码,地址所有者的余额放在里面。每个人的代币余额都是公开可读的。

一、基于以太坊合约的ERC20代币•
Tokens是具备权益凭证属性的区块链应用项目的代币,这些区块链应用项目都是在基础链上发展出来的,具有特定应用场景的DAPP或者智能合约等,Tokens是这些应用链的“代币”集合统称。我们可以理解成:凡是建立在基础链上面的应用项目,它们发行的代币属于Tokens,带有“权益凭证”的属性。•
关键字:代币、权益证明、通证• Token实现了资产的数字化和价值的流通•
区块链则为Token提供了必要的基础设施

构建代币

让我们直接进入它并构建我们的代币。它将是一个有点标准的千篇一律的ERC20代币。(你会看到这篇文章中那个更标准的。)首先,我们将引入一些依赖关系。OpenZeppelin库是经过实战考验的高质量的solidity合约,可用于扩展和构建合约。

npm install openzeppelin-solidity 

接下来,让我们创建一个新的代币文件:

truffle create contract TNSToken 

truffle在这里生成的默认模板有点过时了,所以让我们更新它:

pragma solidity ^0.4.24;contract TNStoken { constructor() public { }}

到目前为止,代币合约的构造函数应该与合约本身一样被调用,但为了清楚起见,它被更改为constructor。它也应该总是有一个修饰符告诉编译器谁被允许部署和与此合约交互(public意味着每个人)。

这里的 truffle develop
,是开发智能合约运行,最简便的方式,不需要考虑区块链环境。从本地就直接运行了一个私有链环境,这个链只能你本机能访问到,其它机子无法访问。

初始余额

让我们给合约的制造者所有的代币。否则,代币将不会发送给任何人。通过在其末尾添加以下行来更新constructor

balances[msg.sender] = totalSupply_; 

在 Ropsten测试链环境下:• 新建用户账户,搭建节点○ Personal.newAccount()•
导入原有账户,搭建节点

以太坊主网地址:

相关参数获取:• 测试链的机子ip 和 端口 (–rpcport
“8545”,该命令指定发布出去的端口)• 合约地址 在build
文件夹下面找对应的合约名称的文件• ABI信息 在build
文件夹下面找对应的合约名称的文件

当前有两类账户类型:•
外部账户EOA,可简单认为是“人类用户”,有私钥和余额,交易发送前会用私钥先签名。例如
钱包。•
合约账户CA,合约部署之后,会随之对应有一个账户,由余额和相应的合约状态数据。它由外部消息来触发执行。触发源来自外部账户或其他合约账户。

  • 最为流行的智能合约开发、测试和部署框架。经常与 Ganache (也是由 Truffle
    团队开发) 一起搭配使用。相关工具-Truffle boxes – 一些打包好的组件•
    Vscode (开发solidity的智能合约,轻量级代码编辑器)○ Visual Studio Code –
    ,好多支持 solidity 的插件。○ 语言-Solidity –
    官方推荐以太坊智能合约开发语言,也是目前最为主流的智能合约语言。相关下载,搜索后进入官网,建议先在官网把相关文档过一遍

三、基于ERC20 编写智能合约什么是智能合约•
智能合约就是区块链上一个包含合约代码和存储空间的虚拟账户。简单说,就是一个协议,会在区块链检测到某些特定数据条件下时触发。•
基于 消息和事件 进行触发合约执行

同步区块的方式:Full Node 全节点Lite Node
轻节点,只同步个人的账户信息,该模式不能挖矿Fast
同步区块头的模式,速度快一些

来自 <;

常见的编码套路有:•
对于支付,优先采用“取款”,而不是“转账”(即send或transfer),避免接收合约恶意fallback函数。•
对于支付,采用CDI模式,避免重入问题。即:○ 检查 -> 更改本合约状态
->支付。• 善用Modifier进行权限控制。•
使用mapping类型保存合约数据,甚至为了方便升级,单独分离出两类:○
数据合约,仅包含mapping,保留操作mapping的函数,客观上类似数据表。○
控制合约,仅包含逻辑控制,通过数据合约的接口操作数据。若逻辑有问题,只需升级本合约即可,数据仍然得以保留。

六、测试链的选择:Ropsten 以太坊官方提供的测试网络,使用pow共识机制Kovan
使用权威证明的共识机制,简称poaRinkeby
以太坊官方提供的测试网络,使用poa共识机制

相关文章