头图

Solidity入门1

blockgeek

Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言,为了体验Solidity语言在智能合约应用场景广泛性,跟着Solidity官方文档中文社区学习做两个简单例子以熟悉安装、配置、使用集成开发环境和基础智能合约实际应用。

标准以太坊货币例子合约熟悉开发环境

任何语言都一样,让我们来快速体验一下Solidity的helloworld吧,把前几天学到的货币合同copy来直接上环境一睹为快:
1. 访问https://remix.ethereum.org/网站,初始加载比较慢,可以随便点点最左边的图标看看有些什么功能;
2. 点File explorers在default_workspace边上,点Create创建一个新空间workspace_mark;点Create New File在contracts下创建一个合约;

3. 将如下代码保存在合约中;

pragma solidity ^0.4.16;

interface tokenRecipient { 
    function  receiveApproval(address _from, uint256 _value, address _token, bytes _extraData)  external; 
    
}

contract t_first_Token {
    string public name;
    string public symbol;
    uint8 public decimals = 18;  // 18 是建议的默认值
    uint256 public totalSupply;

    mapping (address => uint256) public balanceOf;  //
    mapping (address => mapping (address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Burn(address indexed from, uint256 value);


     function t_first_Token(uint256 initialSupply, string tokenName, string tokenSymbol) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);
        balanceOf[msg.sender] = totalSupply;
        name = tokenName;
        symbol = tokenSymbol;
    }


    function _transfer(address _from, address _to, uint _value) internal {
        require(_to != 0x0);
        require(balanceOf[_from] >= _value);
        require(balanceOf[_to] + _value > balanceOf[_to]);
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        Transfer(_from, _to, _value);
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    function transfer(address _to, uint256 _value) public returns (bool) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }

    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);
        balanceOf[msg.sender] -= _value;
        totalSupply -= _value;
        Burn(msg.sender, _value);
        return true;
    }

    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);
        require(_value <= allowance[_from][msg.sender]);
        balanceOf[_from] -= _value;
        allowance[_from][msg.sender] -= _value;
        totalSupply -= _value;
        Burn(_from, _value);
        return true;
    }
}

4. 选择Solidity Compiler出新界面后,点击Compile t_first_token.sol编译智能合同,点击Publish on Swarm将智能合同发表;
5. Deploy按下图三步发布合同到JavaScript vm中;
发布初始构造需要货币总量、币名和币编号。

6. 操作JavaScript vm中合同的函数并查询变量;
使用MetaMask钱包等的地址0x7a7644C0F817eb94C823781E20B2F2EcE2916967调用(JavaScript vm要进行格式验证)。

7. 这样Solidity编辑的智能合同,一个仿以太币就show出来了。

合同间调用例子看智能合约的变化

1. 学习生产环境的配置看考Hardhat + VS code文档
安装运行hardhat:
npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers
npx hardhat

由上到下运行如下命令:
npx hardhat accounts
npx hardhat compile
npx hardhat test
npx hardhat node
node scripts/sample-script.js
npx hardhat help

npx hardhat test可以得到真正的helloworld合同输出
Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'

npx hardhat node
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

2. 将上面t_first_token.sol合同转移到hardhat环境中运行
合同升级到0.7+,修改相应代码如下( //修改版本升级)

  • wanning:加license标签,constrctor 去掉public修饰
  • error:版本,加memory修饰,比较adress,this 被adress强制转换等
//SPDX-License-Identifier: Unlicense 
//修改版本升级
pragma solidity >=0.7.0;//修改版本升级

interface tokenRecipient { 
    function  receiveApproval(address _from, uint256 _value, address _token, bytes memory _extraData)  external; //修改版本升级
    
}

contract t_first_token {
    string public name;
    string public symbol;
    uint8 public decimals = 18;  // 18 是建议的默认值
    uint256 public totalSupply;

    mapping (address => uint256) public balanceOf;  //
    mapping (address => mapping (address => uint256)) public allowance;

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Burn(address indexed from, uint256 value);


     //function t_first_token(uint256 initialSupply, string memory tokenName, string memory tokenSymbol) public {
constructor(uint256 initialSupply, string memory tokenName, string memory tokenSymbol)  {//修改版本升级
        totalSupply = initialSupply * 10 ** uint256(decimals);
        balanceOf[msg.sender] = totalSupply;
        name = tokenName;
        symbol = tokenSymbol;
    }


    function _transfer(address _from, address _to, uint _value) internal {
        require(_to != 0x0000000000000000000000000000000000000000);//修改版本升级
        require(balanceOf[_from] >= _value);
        require(balanceOf[_to] + _value > balanceOf[_to]);
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
       emit Transfer(_from, _to, _value);
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    function transfer(address _to, uint256 _value) public returns (bool) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    function approveAndCall(address _spender, uint256 _value, bytes memory _extraData) public returns (bool success) {//修改版本升级
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, address(this), _extraData);//修改版本升级
            return true;
        }
    }

    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);
        balanceOf[msg.sender] -= _value;
        totalSupply -= _value;
       emit Burn(msg.sender, _value);
        return true;
    }

    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);
        require(_value <= allowance[_from][msg.sender]);
        balanceOf[_from] -= _value;
        allowance[_from][msg.sender] -= _value;
        totalSupply -= _value;
       emit Burn(_from, _value);
        return true;
    }
}

3.添加计数合同,更新t_first_token.sol添加变量
test测试合同中的函数调用

const { expect } = require("chai");

describe("Greeter", function() {
  it("Should return the new greeting once it's changed", async function() {
    const Greeter = await ethers.getContractFactory("Greeter");
  
    const greeter = await Greeter.deploy("Hello, world!");
    await greeter.deployed();

    expect(await greeter.greet()).to.equal("Hello, world!");

    const setGreetingTx = await greeter.setGreeting("Hola, mundo!");
    
    // wait until the transaction is mined
    await setGreetingTx.wait();

    expect(await greeter.greet()).to.equal("Hola, mundo!");
  });
});

describe("t_first_token", function() {
  it("Should return mane", async function() {
    const _t_first_token = await ethers.getContractFactory("t_first_token");
  
    const t_first_token = await _t_first_token.deploy(2000,"markcion","18188");
    await t_first_token.deployed();

    expect(t_first_token.burn(111));

  });
});

describe("t_first_token/Greeter", function() {
  it("Should return t_first_token/Greeter", async function() {
    const _t_first_token = await ethers.getContractFactory("t_first_token");
    const t_first_token = await _t_first_token.deploy(2000,"markcion","18188");
    await t_first_token.deployed();
   
    

    const Greeter = await ethers.getContractFactory("Greeter");
    const greeter = await Greeter.deploy("Hello, world!");
    await greeter.deployed();


    expect(t_first_token.inc());
     expect(greeter.inc());
     expect(greeter.inc());
  });
});

npx hardhat test
Greeter
Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'
✓ Should return the new greeting once it's changed (1098ms)
t_first_token
Deploying a tokenName: markcion
✓ Should return mane (122ms)
t_first_token/Greeter
burn-totalSupply: 1999999999999999999889
Deploying a tokenName: markcion
t_first_token m: 2
Deploying a Greeter with greeting: Hello, world!
✓ Should return t_first_token/Greeter (173ms)

3 passing (1s)

Greeter m: 2
Greeter m: 3

4. 调用关系并简单分析
Solidity中,如果只是为了代码复用,我们会把公共代码抽出来,部署到一个library中,后面就可以像调用C库、Java库一样使用了。但是library中不允许定义任何storage类型的变量,这就意味着library不能修改合约的状态。如果需要修改合约状态,我们需要部署一个新的合约,这就涉及到合约调用合约的情况。
合约调用合约有下面4种方式:

  • CALL
  • CALLCODE
  • DELEGATECALL
  • STATICCALL

CALL vs. CALLCODE
CALL和CALLCODE的区别在于:代码执行的上下文环境不同。
具体来说,CALL修改的是被调用者的storage,而CALLCODE修改的是调用者的storage。

CALLCODE vs. DELEGATECALL
实际上,可以认为DELEGATECALL是CALLCODE的一个bugfix版本,官方已经不建议使用CALLCODE了。
CALLCODE和DELEGATECALL的区别在于:msg.sender不同。
具体来说,DELEGATECALL会一直使用原始调用者的地址,而CALLCODE不会。


欢迎区块链行业志同道合的小伙伴添加小极微信,加入blockgeek区块链技术交流群,共同推动区块链技术普及和发展~

image.png

阅读 412
1 声望
2 粉丝
0 条评论
你知道吗?

1 声望
2 粉丝
文章目录
宣传栏