我才是二亮

我才是二亮 查看完整档案

北京编辑  |  填写毕业院校  |  填写所在公司/组织 blog.2liang.me 编辑
编辑

哈哈哈

个人动态

我才是二亮 评论了文章 · 2018-08-20

以太坊智能合约开发:让合约接受转账

以太坊智能合约开发:让合约接受转账

在以太坊智能合约开发中,通常会有向合约地址进行转账的需求,那么有几种向合约地址进行转账的方式呢?

有三种方式:

  • 部署合约时转账
  • 调用合约提供的方法
  • 直接向合约地址进行转账

但有一个问题,以太坊的智能合约默认是拒绝来自任何地址的转账,那么如何让合约能够支持接收转账呢?

1、部署转账

在进行合约开发时,如果想要在部署时,直接向该合约进行转账,只需要给构造函数中添加payable修饰符。

示例:

contract Test {
    
      // 构造函数添加payable修饰符即可
      function Test() payable {
        // 构造函数其他逻辑代码  
    }
}

2、执行合约转账

执行合约转账,则需要给你需要支持转账功能的方法添加payable修饰符

示例:

contract Test {
    
      function getBalance() payable {
        // 其他逻辑
    }
}

3、直接转账

支持直接转账,需要借助后备函数(fallback function),只需要为后备函数添加 payable 修饰符

示例:

contract Test {
    
      function () payable {
        // 其他逻辑
    }
}

附录

查看原文

我才是二亮 分享了头条 · 2018-05-07

收录431种基于以太坊ERC20的代币智能合约,可以找到自己关注的币种,做你想做的任何事情

赞 0 收藏 2 评论 0

我才是二亮 回答了问题 · 2018-03-27

解决metamask的私钥是不是保存在自己的服务器?

私钥或者助记词都仅仅存在于你的本地,metamask在你本地通过你的私钥对交易进行签名后,再发送到以太坊网络上。

关注 3 回答 2

我才是二亮 发布了文章 · 2018-03-26

以太坊标准令牌系列之同质化令牌ERC20

0x00 写在前面

众所周知,以太坊在现阶段最大的应用就是令牌发行,而在以太坊中有很多类型的令牌,最著名的当属ERC20了,但是对于其他几种令牌类型,可能还有一些朋友不知道,所以最近规划了一个系列,就是以太坊标准令牌系列。

目前市面上,凡是基于以太坊的令牌,在交易所上线交易的均是ERC20令牌,那么今天我们就来聊聊ERC20令牌的标准方案吧。

0x01 ERC20标准制定动机

在基于以太坊发行令牌时,如果各个令牌发行方都使用自有标准去发行令牌,那对于钱包开发者以及交易所对接成本是极其高昂了,因为他们需要为每一种令牌去独立进行对接,为了降低钱包开发者以及交易所的对接成本,以太坊社区制定了一个关于令牌的发行标准。

该标准中主要包含了,令牌的转移,地址余额的获取等方法。

0x02 ERC20标准规范

一个令牌的合约,一般需要令牌的发行量,每个地址的余额,令牌的转移等方法, 而ERC20标准就是将这些最常用又是必不可少的方法,对此进行标准化,方便开发者进行令牌合约的开发,也方便钱包开发者以及交易所对接成本降到最低。

其中,定义了三类,方法、属性、事件。

下面介绍这些标准方法:

A. 方法(Method)

1、totalSupply:令牌总量

函数原型
function totalSupply() constant returns (uint256 totalSupply)

方法 该方法用于获取令牌总发行量

2、balanceOf:获取余额
函数原型
function balanceOf(address _owner) constant returns (uint256 balance)

方法 该方法用于获取地址 _owner 的令牌余额

3、transfer:转账

函数原型
function transfer(address _to, uint256 _value) returns (bool success)

方法 该方法用于将调用令牌合约的地址中的_value个令牌转给_to 地址

4、transferFrom:转账

函数原型
function transferFrom(address _from, address _to, uint256 _value) returns (bool success)

方法 该方法用于从_from 地址中发送_value 个令牌给_to地址。

当你希望能够使用其他智能合约控制你的令牌转移,则可以使用transferFrom方法,而使用transferFrom方法有一个前提条件,那就是需要调用者需要得到 _from 地址的授权,才可以进行令牌转移的操作。而如何进行授权,我们接下来会介绍。

5、approve:授权

函数原型
function approve(address _spender, uint256 _value) returns (bool success)

方法 允许 _spender 地址从你的账户中转移 _value 个令牌到任何地方。

当你设置了一个 _value 之后,_spender 地址可以分任何多次将令牌进行转移,直至_value为0.

6、allowance:获取被授权令牌余额

函数原型
function allowance(address _owner, address _spender) constant returns (uint256 remaining)

方法 获取 _owner 地址授权给 _spender 地址可以转移的令牌的余额。

B. 事件(Event)

事件是EVM内置的日志功能,而且在DAPP中,我们可以通过JS来监听事件的回调。在ERC-20令牌中,定义了以下事件:

1、Transfer:转移令牌
事件定义
event Transfer(address indexed _from, address indexed _to, uint256 _value)

当进行令牌转移时,需要触发调用该事件。其中记录了令牌发送者_from,令牌接受者_to ,令牌发送量_value.

2、Approval:授权事件
事件定义
event Approval(address indexed _owner, address indexed _spender, uint256 _value)

当进行授权时,需要触发调用该事件,其中记录了授权者_owner,被授权者_spender,授权令牌量_value

0x03 ERC20令牌接口

通过以上的标准,我们可以了解到一个遵守ERC20令牌标准的令牌合约需要实现的方法,以下是通过规范实现的一个ERC20令牌的接口。

contract EIP20Interface {
    
    ///////////////////////////// 方法 ///////////////////////////////////
    
      // 获取令牌发行量
    // 注意:constant的修饰符是提示该方法中不能进行变量的修改。
    //      但编译器不会强制校验。
    // @return uint256 totalSupply 总发行量
    function totalSupply() constant returns (uint256 totalSupply)

       // 获取指定地址
    // @param address _owner 想要获取的地址
    // @return uint256 balance 令牌余额
    function balanceOf(address _owner) public view returns (uint256 balance);

    // 从`msg.sender`中发送`_value`个令牌给`_to` 
    // @param address _to 接收令牌的地址
    // @param uint256 _value 发送的令牌数量
    // @return bool success 发送令牌成功状态
    function transfer(address _to, uint256 _value) public returns (bool success);

    // 从`_from`地址发送`_value`令牌到`_to`地址
    // 需要满足条件,需要被`_from`地址授权给`msg.sender`
    // @param address _from 发送者地址
    // @param address _to 接收者地址
    // @param uint256 _value 发送的令牌数量
    // @return bool success 发送令牌成功状态
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

    // `msg.sender`授权`_spender`地址可以任意转移`_value`数量的令牌
    // @param address _spender 被授权发送令牌的地址
    // @param uint256 _value 授权发送令牌的数量
    // @return bool success 授权成功状态
    function approve(address _spender, uint256 _value) public returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    // 获取被授权限额
    // @param address _owner 令牌所有者的账户
    // @param address _spender 令牌被授权者账户
    // @return uint256 remaining 剩余可发送的令牌数量
    function allowance(address _owner, address _spender) public view returns (uint256 remaining);
    
    ///////////////////////////// 事件 ///////////////////////////////////
    // 令牌转移事件 当发生令牌的转移时,需要调用该事件
    event Transfer(address indexed _from, address indexed _to, uint256 _value); 
    // 授权转移事件 当进行授权时,需要触发该事件
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

0x04 ERC20代码示例

在标准的基础上,有很多代码的实现方法,比如有的在代码中实现空投,有的在实现锁定,有的实现挖矿等等,但是最常规的实现已经有了官方的实现代码,也有很多组织实现了一些范例,如果没有定制化的地方,完全可以直接采用这些代码去创建ERC20令牌。

示例代码:

pragma solidity ^0.4.18;

contract ERC20 {

    // 定义一个mapping 存储各个地址的令牌
    mapping (address => uint256) public balances;
    // 定义一个mapping 存储授权详情
    mapping (address => mapping (address => uint256)) public allowed;
    
    // 以下参数非必须,但是尽量添加,大多数钱包会通过此获取相关信息

    // 令牌发行总量
    uint256 public totalSupply;

    // 令牌名称,如 OmiseGO
    string public name;      
    // 支持的小数位数
    // 因为在EVM中对浮点数的支持很差,在令牌的创建中直接采用整数
    // 然后通过该字段进行小数的处理
    uint8 public decimals;                
    // 令牌简称,如 OMG
    string public symbol;              

    // 令牌合约的构造函数
    // 在solidity中,和合约名称一致的方法为构造函数,在第一次创建合约时,仅执行一次。
    function ERC20(
        uint256 _totalSupply,    // 令牌创建总量
        string _name,        // 令牌名称
        uint8 _decimals,    // 支持小数位数
        string _symbol        // 令牌简称
    ) public {
        // 给创建者账户初始化令牌
        balances[msg.sender] = _totalSupply;               
        // 设置令牌发行量
        totalSupply = _totalSupply;                        
        // 设置令牌名称
        name = _name;                                   
        // 设置令牌支持小数位数
        decimals = _decimals;                            
        // 设置令牌简称
        symbol = _symbol;                               
    }

    /**
     * 获取令牌总发行量
     * @return uint256 totalSupply 发行总量
     */
    function totalSupply() constant returns (uint256 totalSupply) {
        return totalSupply;
    }

    /**
     * 转移令牌
     * @param address _to 令牌接收者地址       
     * @param uint256 _value 发送令牌数量
     * @return bool success 发送成功状态
     */
    function transfer(address _to, uint256 _value) public returns (bool success) {
        // 判断发送者余额是否充足
        require(balances[msg.sender] >= _value);
        // 从发送者余额中减去`_value`数量的令牌
        balances[msg.sender] -= _value;
        // 给接收者账户中添加`_value`数量的令牌
        balances[_to] += _value;
        // 记录令牌转移的事件
        Transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * 转移令牌(授权)
     * @param address _from 令牌发送者地址
     * @param address _to 令牌接收者地址
     * @param uint256 _value 令牌发送数量
     * @return bool success 方法执行状态
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {

        // 其中`msg.sender`是合约方法调用者的地址

        // 获取`_from`地址授权给`msg.sender`地址的可转移令牌余额
        uint256 allowance = allowed[_from][msg.sender];
        
        // 判断`_from`地址余额是否充足以及授权转移令牌是否充足
        require(balances[_from] >= _value && allowance >= _value);
        
        // 从`_from`地址减去`_value`数量的令牌
        balances[_from] -= _value;
        
        // 从授权余额中减去`_value`数量的令牌
        allowed[_from][msg.sender] -= _value;

        // 给`_to`地址添加`_value`数量的令牌
        balances[_to] += _value;

        // 记录转移令牌的事件
        Transfer(_from, _to, _value);
        return true;
    }

    /**
     * 获取`_owner`地址的令牌余额
     * @param address _owner 要获取余额的地址
     * @return uint256 balance 返回`_owner`地址的余额
     */
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return balances[_owner];
    }   

    /**
     * 授权令牌转移方法
     * @param address _spender 被授权地址
     * @param uint256 _value 授权可转移的数量
     * @return bool success 方法执行状态
     */
    function approve(address _spender, uint256 _value) public returns (bool success) {
        // `msg.sender`授权`_spender`地址转移`_value`数量的令牌
        allowed[msg.sender][_spender] = _value;

        // 记录授权事件
        Approval(msg.sender, _spender, _value);
        return true;
    }

    /**
     * 获取被授权的令牌余额
     * @param address _owner 授权地址
     * @param address _spender 被授权地址        
     * @return uint256 remaining 可转移的令牌余额
     */
    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }   
}

0x05 写在后面

大多数在交易所交易的令牌的合约代码就这么简单,其实每一个方法拆分开来都是最简单的编程代码,而核心的处理都被EVM进行了封装,以太坊在令牌发行方面确实极大的解放了人类,简单几十行代码就可以发行一个令牌。ERC20令牌又被成为同质化令牌,就是每个令牌都是一致的,无法区分,而市场上现在冒出了很多以太猫,以太狗的游戏,而这里面也是使用以太坊的令牌来实现的,但是他们选择的不是ERC20令牌,而是被成为非同质化的令牌,被称为ERC721令牌。

下期,我们一起来聊非同质化令牌ERC721。

喜欢,不要说话,扫我~

qrcode_for_gh_0f12fe5ef5fd_258.jpg

查看原文

赞 1 收藏 0 评论 0

我才是二亮 发布了文章 · 2018-03-19

如何使用web3部署以太坊智能合约

0x00 起始

大多数人在初学智能合约开发的时候,都是选择使用remix进行合约的开发以及部署。remix是集Solidity的编辑器,编译器,部署于一身的集成开发工具,非常方便,也非常好用。之前一直使用Remix或者truffle,最近使用web3进行智能合约的部署,分享下。

0x01 准备工作

在使用web3进行合约的部署,一般需要使用准备以下几个库:

1、 solc

solc 是以太坊官方出的一款Solidity语言开发的智能合约的编译工具,可以通过solc 获得部署合约时所要使用的 bytecodeabi

2、web3.js

web3.js是以太坊官方实现的一个使用javascript与以太坊客户端进行交互的js库,web3.js可以与任何暴露RPC层的以太坊节点协同工作。

0x02 使用solidity编写智能合约代码

本文主要讨论web3的智能合约部署,不涉及solidity语言的讨论,所以我们使用一个非常简单的智能合约来学习下面的部署,将自己的名字写入区块链中:

pragma solidity ^0.4.16;

contract Name {
    string public name;
    
    // 构造函数 合约部署时执行
    function Name(string _name) public {
        name = _name;
    }
    
    // 获取名字
    function getName() view public returns(string) {
        return name;
    }
}

0x03 使用solcjs编译智能合约

如果想要使用web3来部署合约,需要先获得合约的bytecode以及合约的abi,而编译可以使用solcjs进行。

npm install -g solc

安装成功后,我们可以通过命令行编译代码,获得code以及abi。

# 获得code
solcjs --bin name.sol

# 获的abi
solcjs --abi name.sol

0x04 部署前web3注入

1、引入web3.js

引入web3.js有两种方法,一种使用nodejs,一种直接使用浏览器引擎。

nodejs
npm install web3
Browser module
# 项目中直接引入 `web3.min.js`
bower install web3

2、如何使用web3

其实web3就是对以太坊的json-rpc接口使用javascript进行了一次封装,既然是rpc,我们在使用时,必须连接一个服务器,也就是以太坊的支持json-rpc的节点。在这里,我们一般把连接json-rpc节点称为注入以太坊节点。注入节点有两种方式。

- 注入自有节点或者开放节点

这种方式的注入,我们需要搭建一个自己的节点,通过自己的节点与以太坊网络进行交互,代码如下:

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

其中的http://localhost:8545就是你自己的节点的地址,但是因为以太坊全节点的数据量越来越大导致同步一个全节点数据需要非常长的时间以及很大的硬盘容量,这对于普通用户是非常头疼的。

目前有一些开放的提供全节点和测试网络节点的服务商,其实比较好用,可以避免自己去同步整个以太坊网络,而只需要专心去开发自己的应用即可,提供一个节点服务。多链科技旗下的多链节点就是提供这个服务的。

// 多链节点
https://node.duolian.io/

2018-03-19_2.18.23.png

- 使用MetaMask等浏览器插件

MetaMask是一个以太坊钱包的浏览器插件,该插件提供自己的web3实例,当用户在浏览器中安装了MetaMask,MetaMask会自动注入一段js,然后将自己的web3实例注入到了浏览器中,所以可以直接使用该web3实例。代码如下:

web3 = new Web3(web3.currentProvider);
注入web3代码

当浏览器中已经拥有了web3实例,那么我们就直接使用已存在的实例,如果不存在,再去连接我们自己的web3实例。

if (typeof web3 !== 'undefined') {
  web3 = new Web3(web3.currentProvider);
} else {
  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}

0x05 通过web3部署合约

通过solcjs获取了合约的code以及abi,浏览器中也成功注入了web3,此时我们只需要通过web3去进行合约的部署了。

var _name = /* var of type string here */ ;
var nameContract = web3.eth.contract("使用solcjs编译获得的abi");
var name = nameContract.new(
   _name,
   {
     from: web3.eth.accounts[0], 
     data: '使用solc编译获得的code', 
     gas: '4700000'
   }, function (e, contract){
    console.log(e, contract);
    if (typeof contract.address !== 'undefined') {
         console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
    }
 })

0x06 最终代码

因为本文在部署时,使用MetaMask的web3实例,因为MetaMask的web3不支持同步调用,所以在实例化web3时,代码有所区别,相关js代码如下:

var Web3 = require('web3');
getWeb3 = new Promise(function(resolve) {
    window.addEventListener('load', function() {
        var results;
        var web3 = window.web3;
        if (typeof web3 !== 'undefined') {
            // Use Mist/MetaMask's provider.
            web3 = new Web3(web3.currentProvider);
            results = {
                web3: web3
            };
            console.log('Injected web3 detected.');
            resolve(results);
        } else {
            alert('请安装MetaMask插件并解锁您的以太坊账户');
        }
    })
});
var web3;
getWeb3.then(function(results) {
    web3 = results.web3;
});

// 部署的方法
function deploy()
{
    var _name = "二话区块链" ;
    var nameContract = web3.eth.contract(使用solc编译获得的abi);
    var name = nameContract.new(
        _name,
        {
            from: web3.eth.accounts[0],
            data: '使用solc编译获得的code',
            gas: '288628',
            gasPrice: 4
        }, function (e, contract){
            console.log(e, contract);
            if (e !== 'undefined') {
                if (typeof contract.address !== 'undefined') {
                    console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
                } else {
                    console.log('Contract mined! transactionHash: ' + contract.transactionHash);
                }
            }
        });
}

谢谢大家的支持,如果觉得不错,欢迎转发~

如果喜欢,别说话,扫我~

qrcode_for_gh_0f12fe5ef5fd_258.jpg

查看原文

赞 6 收藏 7 评论 0

我才是二亮 分享了头条 · 2018-03-19

使用web3部署智能合约,看这篇就够了~

赞 1 收藏 2 评论 2

我才是二亮 分享了头条 · 2018-03-01

大多数初学区块链技术的朋友,都是从比特币和以太坊的技术原理来入手的。这两个项目有很多相同之处,但是他们在细节的实现上是有挺多的区别的,今天我们就来说说账户模型的区别。比特币和以太坊在实现余额的处理上,采用了不同的机制,比特币采用了UTXO未花费交易输...

赞 1 收藏 2 评论 0

我才是二亮 分享了头条 · 2018-02-25

如何实现在imtoken中添加代币合约地址即实现空投,看这个就够了~

赞 0 收藏 1 评论 0

我才是二亮 回答了问题 · 2018-02-13

区块链有激励机制吗

以比特币为例:比特币中的挖矿就是在记录交易信息,而每次挖成功的块中的第一条交易被称为coinbase交易,这个交易中是比特币网络给矿工的奖励,这个奖励每四年减半,我们已经到了第三个四年了,所以,每个区块的奖励是12.5个比特币。

关注 9 回答 7

认证与成就

  • 获得 117 次点赞
  • 获得 57 枚徽章 获得 5 枚金徽章, 获得 20 枚银徽章, 获得 32 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2013-11-16
个人主页被 1.2k 人浏览