《智能合约开发课》学习7:代投后发给多个参投方

in #cn7 years ago (edited)

img最近报名参加了硅谷区块链举办的《智能合约开发课》第二期培训班,根据培训要求,不能透露课程的内容,但我会在steemit上记录我的成长过程。

根据最近学习的内容,我编了一个应用场景:

几个人合伙凑出几个ETH,发给代投方agent;代投方发放token后,按份额发给每个参与者

1)结构struct

这个需求里涉及了多个参与者,我们需要记录其钱包地址和参投的份额。Solidity支持struct结构类型,这点与C语言非常相似,建立一个参与者的结构后,可以记录每个参与者的地址和参投数量。

struct Participator {
    address addr;  
    uint amount;
}

2)数组

Solidity支持定长数组和动态数组,这里我们的参投人数是不定的,所以用动态数组。

Participator []participators;

在动态数组中增加一个元素用push()函数。参投者向合约地址里支付ETH后,需要记录其地址和参加的份额。这里需要在addFund()函数中增加这样一行。

participators.push(Participator(msg.sender, msg.value));

3)安全考虑

涉及到转账操作时要特别注意,不能让无关人员执行这些函数,通常的做法是声明一个成员变量address owner,然后在构造函数中记录合约的创建者owner。

构造函数的名称与合约名称一致,并且不带任何参数。

function CoinProxy() {
    owner = msg.sender;
}

然后在各个函数中判断函数的调用者是否有权限执行转账操作,如果没有权限,中止函数的执行。

if(msg.sender != owner) {
    revert();
}

4)异常处理及状态回滚

solidity在执行过程中如果遇到异常要保持原子操作的完整性,需要将各种状态恢复成调用前的状态,需要用到revert()函数。在比较早的solidity版本中都用throw(),现在统统用revert()。

在solidity中经常要进行这些类似的判断,如果都用if语句,则显得非常臃肿,可以把上面的if语句用require写成一行。

require(msg.sender == owner);

这种表达方式在solidity中大量存在,语法精练,语义清晰。

5)统计参投的总币数

for语法与C语言一样,没什么可讲的。

uint total = 0;
for(uint i = 0; i<participators.length; i++){
    total += participators[i].amount;
}

6)发出token

收到代投方换回的token后,要发给每个参投方。这里我还不知道如何发放ERC-20代币,先假设发放balance里的ether吧。这里按份额发放即可。

for(i = 0; i<participators.length; i++){
    participators[i].addr.transfer(this.balance * participators[i].amount / totalEthers);
}

主要的步骤就是这些,程序里还有一些问题没有考虑,没有考虑代投过程的起止时间,如果换回token后,仍有人追加资金,份额的计算是有问题的。这些细节留着以后再考虑。

完整的代码:

pragma solidity ^0.4.14;

contract CoinAgent {
    // 与C语言类似,支持结构类型
    struct Participator {
        address addr;  
        uint amount;
    }
    
    //用remix中生成的第5个测试地址,收集到的ETH发给他
    address agent = 0xdd870fa1b7c4700f2bd7f44238821c26f7392148; 

    // 参投方,动态数组
    Participator []participators;
    
    address owner;
 
    function CoinAgent() {
        owner = msg.sender;
    }
    
    
    // 每个参投方调用这个函数参投
    function addFund() payable returns(uint) {
        participators.push(Participator(msg.sender, msg.value));
        return this.balance;
    }
    
    // 送给代投方 
    function sendToAgent() {  
        if(msg.sender != owner) {
            revert();
        }
        agent.transfer(this.balance);
    }
    
    // 把tokens按照参加份额发给每个参投人  
    // 当前还不知道如何发ERC-20代币,先发ETH
    function sendTokens() {
        require(msg.sender == owner);
        uint total = 0;
        for(uint i = 0; i<participators.length; i++){
            total += participators[i].amount;
        }
    
        // 前面定义的i变量在整个函数中都可以访问   
        for(i = 0; i<participators.length; i++){
            participators[i].addr.transfer(this.balance * participators[i].amount / total);
        }
    }
}

本文由币乎(bihu.com)内容支持计划奖励