编写合约实例-投资者

一:合约功能

1.添加投资者到mapping
2.设置投资者的资金
3.做事件监听

二:编写合约

pragma solidity ^0.4.0;
contract StructDemo{
    struct Funder{
        address add;
        uint amount;
    }

    mapping (uint => Funder) public funders;

    uint public numFunder;

    event e(string _str, address _add, uint _u);

    function newFunder(address _add, uint _amount) public returns (uint){
        ++numFunder;
        funders[numFunder] = Funder(_add, _amount);
        emit e("newFunder", _add, _amount);
    }

    function setFunder(uint _u, uint _amount) public {
        Funder storage f = funders[_u];
        f.amount = _amount;
        emit e("setFunder", f.add, f.amount);
    }
}

三:知识点

3.1 struct、mapping

3.2 public

3.3 event

事件是以太坊虚拟机(EVM)日志基础设施提供的一个便利接口。当被发送事件(调用)时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并记录到区块链中.
来捋这个关系:区块链是打包一系列交易的区块组成的链条,每一个交易“收据”会包含0到多个日志记录,日志代表着智能合约所触发的事件。

在DAPP的应用中,如果监听了某事件,当事件发生时,会进行回调。
不过要注意:日志和事件在合约内是无法被访问的,即使是创建日志的合约

3.4 emit

引入emit背景:

ERC20 token标准介绍了一种Transfer事件以及一个transfer()方法。
它们的调用语法不完全相同:
transfer(address to, uint value);
Transfer(address from, address to, uint256 _value);

但是这种相似足够引起混淆。
对未来的Solidity程序员来说这是一个很严重的问题,必须避免意外地将外部调用函数映射到一个
名字相似的事件上,而这导致了去年的DAO攻击。有人建议在事件名前面加上Log前缀来标识以避免将函数和事件混淆,但是最后还是决定引进一个新的关键字emit。

所以:
event Transfer(address from, address to, uint256 _value);
// …
Transfer(from, to, value);
就变为了:

event Transfer(address from, address to, uint256 _value);
// …
emit Transfer(from, to, value);

这就能够让函数调用和事件日志之间具备了语义上的不同。

Transfer事件:
当token被转移的时候必须触发该事件,包括零值转移。
一个创建新token的合约在给_from地址赋0x0值时必须触发一个Transfer事件event Transfer(address indexed _from, address indexed _to, uint256 _value)

transfer方法:
转移_value个token到地址_to,必须激活Transfer事件,若_from账户余额token不足,则该函数应该抛出异常。注意零值转移必须和普通转移一样必须激活Transfer事件

function transfer(address _to, uint256 _value) returns (bool success)

最近3月8日的版本v0.4.21,引进emit关键字来触发事件,这有助于分清功能和事件,这也是之前遭遇DAO攻击导致以太坊硬分叉并催生经典以太坊ETC的原因之一。

根据solidity版本的注释可知:
一般:支持并推荐使用emit EventName()来明确地调用事件。为了让事件较常规函数调用更突出,应该是用emit EventName()而不是EventName()
来调用事件。
下面这个实例用于触发一个事件:

pragma solidity ^0.4.21;
contract ClientReceipt {

    event Deposit(
        address indexed _from,
        bytes32 indexed _id,
        uint _value
    ); //声明一个事件

    function deposit(bytes32 _id) public payable {
    // Events are emitted using `emit`, followed by
    // the name of the event and the arguments
    // (if any) in parentheses. Any such invocation
    // (even deeply nested) can be detected from
    // the JavaScript API by filtering for `Deposit`.
    //事件被emit触发,括号内有事件名参数和其他参数,通过JS API过滤Deposit可检测到任何类似的调用
    //(即使是深度嵌套也能够检测到)
    emit Deposit(msg.sender, _id, msg.value);
    }
}

这里必须确保编译器版本为0.4.12及以上,若较低的版本编译器会抛出错误。

3.6 storage

引用类型的变量有两种类型,分别是memory(值传递)和storage(指针传递)。

参考博文:

https://blog.csdn.net/huhaoxuan2010/article/details/80088879
https://blog.csdn.net/liyuechun520/article/details/78408588
https://blog.csdn.net/tianlongtc/article/details/80472369
https://blog.csdn.net/liyuechun520/article/details/78408608

猜你喜欢

转载自blog.csdn.net/apple9005/article/details/81812419