solidity语法

在编写sol文件之前要加上
  // SPDX-License-Identifier: MIT 

或者

  // SPDX-License-Identifier: SimPL-3.0

数据类型

特殊变量/全局变量,是全局可用的变量
Description

Solidity 特殊变量/全局变量

Description

Solidity 变量作用域

局部变量的作用域仅限于定义它们的函数,但是状态变量可以有四种作用域类型:

  • public – 公共状态变量可以在内部访问,也可以从外部访问。对于公共状态变量,将自动生成一个 getter 函数。
  • private – 私有状态变量只能从当前合约内部访问,派生合约内不能访问。
  • internal – 内部状态变量只能从当前合约或其派生合约内访问。
  • external - 外部状态变量只能在合约之外调用 ,不能被合约内的其他函数调用。

Solidity 条件运算符

? : (条件运算符 )

如果条件为真 ? 则取值X : 否则值Y

   function getResult() public pure returns(uint){
      uint a = 1; // 局部变量
      uint b = 2;
      uint result = (a > b? a: b);  //条件运算
      return result; 
   }

输出结果

{
	"0": "uint256: 2"
}

循环语句

while循环
   function whilexunhuan(uint loop) public pure returns (uint) {
       uint sum = 0;
       uint i = 1;
       while (i <= loop) {
           sum += i;
           i++;
       }
       return sum;
   }
for循环
   function forXunhuan(uint loop) public pure returns (uint) {
       uint sum = 0;
       for (uint i = 1;i <= loop;i++) {
           sum += i;
       }
       return sum;
   }
do-while循环
   function doWhileXunhuan(uint loop) public  pure returns (uint) {
        uint sum = 0;
        uint i = 1;
        do{
            sum += i;
            i++;
        } while (i < loop);
            return sum;
   }

pure和view

solidity pure函数,也就是纯函数,是指函数不会读取或修改状态。
换言之,solidity pure函数不会操作链上数据。
solidity view函数,也就是视图函数,是指函数只会读取状态,不会修改状态。
换言之,solidity view函数只会读取链上数据,不会修改链上数据。

构造函数

Solidity构造函数是一个特殊函数,它仅能在智能合约部署的时候调用一次,之后就不能再次被调用。
Solidity构造函数常用来进行状态变量的初始化工作。
Solidity编译器中,使用关键词 constructor 作为构造函数。

    uint public user;
    address public owner;

    constructor (uint _user) {
        // 将部署者地址存储到owner变量
        owner = msg.sender;
        user = _user;
    }

onlyOwner修饰符

/**
 * @dev 调用者不是‘主人’,就会抛出异常
 */
modifier onlyOwner() {
  require(msg.sender == owner);
  _;
}
onlyOwner 函数修饰符是这么用的:

contract MyContract is Ownable {
  event LaughManiacally(string laughter);

  //注意! `onlyOwner`上场 :
  function likeABoss() external onlyOwner {
    LaughManiacally("Muahahahaha");
  }
}

Solidity 加密函数

  • keccak256(bytes memory) returns (bytes32) 计算输入的Keccak-256散列。
  • sha256(bytes memory) returns (bytes32) 计算输入的SHA-256散列。
  • ripemd160(bytes memory) returns (bytes20) 计算输入的RIPEMD-160散列。
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) 从椭圆曲线签名中恢复与公钥相关的地址,或在出错时返回零。函数参数对应于签名的ECDSA值: r – 签名的前32字节; s: 签名的第二个32字节; v: 签名的最后一个字节。这个方法返回一个地址。
keccak256加密
    function callkeccak256(string memory a) public pure  returns (bytes memory) {
        bytes memory byteArray = bytes(a);
        bytes32 hash = keccak256(byteArray);
        return abi.encodePacked(hash);
    }

Solidity 不可变量 immutable

Solidity immutable 是另一种常量的表达方式。与常量类似,但是不必硬编码,可以在构造函数时传值,部署后无法改变。
immutable 不可变量同样不会占用状态变量存储空间,在部署时,变量的值会被追加的运行时字节码中, 因此它比使用状态变量便宜的多,也同样带来了更多的安全性。

address public immutable owner = msg.sender;

Solidity 合约继承

virtual 和 override

solidity 引入了 virtual,override 关键字,用于重写函数。
父合约可以使用 virtual 关键字声明一个虚函数,子合约使用 override 关键字来覆盖父合约的方法

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract test1{
  string public name;
  uint public age;
  function getSalary() external pure virtual returns(string memory){
    return "Hello World";
  }
}
contract test2 is test1{
  function getSalary() external pure override returns(string memory){
    return "hahahaha";
  }
}
abstract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract test3{ //抽象合约
    function getTest() public pure virtual returns (string memory);
}
contract test4 is test3 { //实现合约
    function getTest() public pure override returns (string memory) {
        return "I am an implementation class";
    }
}

Solidity 异常处理

Solidity 是通过回退状态的方式来处理异常错误。
Solidity 发生异常时,会撤消当前调用和所有子调用改变的状态,同时给调用者返回一个错误标识。
Solidity 提供了require 、assert 和 revert 来处理异常。

require
    uint a = 8;
    function shuru(uint b) public view returns (uint) {
        require(b == a, "b is not equal to a");
        return 0;
    }

随便输入一个不等于8的数字提示
Description

assert
    function shuru2(uint b) public view returns (uint) {
        assert(a == b);
        return 0;
    }

随便输入一个不等于8的数字提示
Description

require、assert 使用场景

require() 函数用于检测输入变量或状态变量是否满足条件,以及验证调用外部合约的返回值。
require() 语句的失败报错,应该被看作一个正常的判断语句流程不能通过的事件。
assert()语句的失败报错,意味着发生了代码层面的错误事件,很大可能是合约中有一个bug需要修复。

delete

用于将某个变量重置为初始值。对于整数,运算符的效果等同于a = 0。而对于定长数组,则是把数组中的每个元素置为初始值,变长数组则是将长度置为0。对于结构体,也是类似,是将所有的成员均重置为初始值。

    uint data;
    
    function change(uint  i) internal {
        data = i;
    }

    function getData() public returns (uint) {
        delete data;
        return data;
    }
接受函数receive
    // 定义事件
    event Received(address Sender, uint Value);
    // 接收ETH时释放Received事件
    receive() external payable {
        emit Received(msg.sender, msg.value);
    }
回退函数
    event fallbackCalled(address Sender, uint Value, bytes Data);

    // fallback
    function fallback() external payable{
        emit fallbackCalled(msg.sender, msg.value, msg.data);
    }
回退函数fallback和receive区别

简单来说,合约接收ETH时,msg.data为空且存在receive()时,会触发receive();msg.data不为空或不存在receive()时,会触发fallback(),此时fallback()必须为payable。
receive()和payable fallback()均不存在的时候,向合约直接发送ETH将会报错(你仍可以通过带有payable的函数向合约发送ETH)。

触发fallback() 还是 receive()?
           接收ETH
              |
         msg.data是空?
            /  \
          是    否
          /      \
receive()存在?   fallback()
        / \
       是  否
      /     \
receive()   fallback()
特点
  • 一个合约最多存在一个回退函数。
  • 它必须被标记为外部(external)函数。

selfdestruct 自毁函数

文章链接

msg.sender和tx.origin的区别

在Solidity中,msg.sendertx.origin都代表了交易的发送者,但两者的含义和应用场景有所不同。

  1. msg.sender:它代表直接调用智能合约函数的账户地址或智能合约地址。无论是外部账户还是智能合约内部的其他合约,只要是直接发起调用的,其地址都会被记录为msg.sender。这意味着,如果一个合约A内部调用了另一个合约B的一个函数,那么在合约B中,msg.sender将表示合约A的地址。
  2. tx.origin:它代表整个交易过程中最初的那个交易发送方的地址。这通常是一个外部账户的地址,因为只有外部账户的地址才被视为交易的发起者。在智能合约内部,如果一个合约接收到来自外部账户的交易调用,那么在合约内部,tx.origin将表示发起该交易的外部账户地址。

简而言之,msg.sender关注的是直接调用者,而tx.origin关注的是原始交易的发送者。在实际应用中,开发者需要根据具体的场景和需求来决定使用哪一个。

abi编码

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Test {
    uint256 x = 10;
    address addr = 0x13a6D1fe418de7e5B03Fb4a15352DfeA3249eAA4;
    string str = "This is China";
    uint256[2] arr = [1, 2];

    function core(uint256 _x, address _addr, string calldata _str, uint256[2] calldata _arr) public {

    }

    function testEncode() public view returns (bytes memory result) {
        result = abi.encode(x, addr, str, arr);
    }

    function testEncodePacked() public view returns (bytes memory result) {
        result = abi.encodePacked(x, addr, str, arr);
    }

    function testEncodeWithSignature() public view returns (bytes memory result) {
        result = abi.encodeWithSignature("core(uint256,address,string,uint256[2])", x, addr, str, arr);
    }

    function testEncodeWithSelector() public view returns (bytes memory result) {
        result = abi.encodeWithSelector(bytes4(keccak256("core(uint256,address,string,uint256[2])")), x, addr, str, arr);
    }

    function testDecode() public view returns (uint256 _x, address _addr, string memory _str, uint256[2] memory _arr) {
        bytes memory result = testEncode();
        return abi.decode(result, (uint256, address, string, uint256[2]));
    }

}

Description
Description

abi.encodePacked(x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 进行打包编码。在 Solidity 中,当需要将多个类型不同的参数一起传递给一个函数时,可以使用 abi.encodePacked() 函数将这些参数打包成一个字节数组。这样可以减少调用数据的成本,因为打包后的数据只需要占用一个存储空间。
abi.encodeWithSignature() 函数用于将参数编码为字节数组,并附加一个签名。这个签名可以用于在智能合约中调用该函数时进行验证。
具体来说,abi.encodeWithSignature(“core(uint256,address,string,uint256[2])”, x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 按照指定的函数签名 “core(uint256,address,string,uint256[2])” 进行编码,生成一个字节数组。这个字节数组可以作为交易数据或消息体发送给其他智能合约。
需要注意的是,使用 abi.encodeWithSignature() 函数时,需要确保传入的参数类型与函数签名中的参数类型相匹配,否则会导致编码失败。
abi.encodeWithSelector() 函数用于将参数编码为字节数组,并附加一个选择器。这个选择器可以用于在智能合约中调用该函数时进行验证。
具体来说,abi.encodeWithSelector(bytes4(keccak256(“core(uint256,address,string,uint256[2])”)), x, addr, str, arr) 的作用是将参数 x、addr、str 和 arr 按照指定的函数签名 “core(uint256,address,string,uint256[2])” 进行编码,生成一个字节数组。这个字节数组可以作为交易数据或消息体发送给其他智能合约。
需要注意的是,使用 abi.encodeWithSelector() 函数时,需要确保传入的参数类型与函数签名中的参数类型相匹配,否则会导致编码失败。

完结
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值