1 function
view:承诺不修改状态。
pure:纯函数,承诺不会读取或修改状态。
payable:为了接收ether,(fallback)回退函数必须标记为payable。最少需2300gas。
2 log
通过函数来访问低层接口的记录机制log0,log1,log2,log3和log4。 logi获取类型的参数,其中第一个参数将用于日志的数据部分,其他参数用作主题。上面的事件调用可以以与以下相同的方式执行i + 1bytes32。
pragma solidity ^0.4.10;
contract C {
function f() public payable {
uint256 _id = 0x420042;
log3(
bytes32(msg.value),
bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20),
bytes32(uint256(msg.sender)),
bytes32(_id)
);
}
}
3 event
1.event
2.在Dapp的用户接口中用JavaScript顺序调用,从而监听这些事件。
event是合约中可继承的成员。当他们调用时,会导致一些参数在交易日志上存储–在blockchain上的一种特殊的数据结构。
//只需声明事件,不需实现,就能用。
//像函数一样可被继承
外部获取智能合约的状态变化
每次触发事件,都会生成以太坊日志,可以索引
在remix中console面板的log里面生成一条日志
如何使用
event EventName(uint param); //声明事件,通常事件大写开头,函数小写
emit EventName(10); //触发事件
外部DApp监听使用
var ev = contractInstance.EventName();
ev.watch(function(err,result){
result.args.name;
})
wiki.learnblockchain.cn/course/dapp.html
// SPDX-License-Identifier:MIT
// 参考: https://www.bilibili.com/video/BV1BQ4y1k7Gz?spm_id_from=333.337.search-card.all.click
pragma solidity ^0.8;
contract Event{
// event Log1(address sender, uint256 value);
event Log1(address indexed sender, uint256 value); // indexed 索引
string log;
function test() external{
emit Log1(msg.sender, 100); //这种方式消耗gas少,比下面存储少
log = 'dfkg';
}
}
pragma solidity ^0.4.24;
contract testEvent {
constructor() public payable {
}
event Deposit(address _from, uint _value);
function deposit() public payable {
emit Deposit(msg.sender, msg.value);
}
function depositNone() public payable {
}
}
contract testEvent2 is testEvent {
function deposit2() public payable {
emit Deposit(msg.sender, msg.value);
}
}
4 library
库和合约类似,但是它们的目的主要是在给定地址上部署,以及用EVM的CALLCODE特性来重用代码。这些代码是在调用合约的上下文里执行的,例如调用合约的指针和调用合约的存储能够被访问。由于library是一片独立的代码,如果它们显式地提供的话,就仅仅能访问到调用合约的状态变量。
// SPDX-License-Identifier: MIT
pragma solidity ^0.7;
// 0.8版本会自动检查溢出,所以用0.7
library SafeMath{
function add(uint256 x, uint256 y) internal pure returns (uint256){
uint256 z = x + y;
require(z >= x, "overflow");
return z;
}
}
library ArrayExtener{
// 为数组添加扩展
function remove(uint256[] storage arr, uint256 index) public{
arr[index] = arr[arr.length - 1];
arr.pop(); //删除最后一个数
}
}
contract TestArray {
using SafeMath for uint;
using ArrayExtener for uint[]; // 为数组添加一个library
uint public Max = 2**256-1;
uint [] public arr = [1,2,3,4];
function testAdd(uint x, uint y) public pure returns (uint){
return x.add(y);
// SafeMath.add(x,y); //或者这样写
}
function testArr() public{
// for (uint i = 0; i < 4; i++){
// arr.push(i);
// }
arr.remove(1);
}
}
5 interface
interface类似于抽象合约,但它们不能实现任何功能。还有其他限制:
无法继承其他合约或接口。
所有声明的函数必须是external的。
无法定义构造函数。
无法定义变量。
无法定义结构。
interface基本上限于合约ABI可以表示的内容,并且ABI和interface之间的转换应该是可能的,而不会丢失任何信息。
如果是接口类型,尽量加I开头
pragma solidity ^0.5.0;
// 调取外部的dog_cat合约
interface IanimalEat{
function eat() external returns(string memory);
}
contract animal is IanimalEat{
//可以调取外部的合约方法
function test(address _addr) public returns(string memory){
IanimalEat generalEat = IanimalEat(_addr);
return generalEat.eat();
}
//可以改写
function eat() external returns(string memory){
return "eat eat eat";
}
}
6 抽象合约
抽象合约前面加A(abstract)
6.1合约存在没有函数体(实现)的函数。
6.2合约不能通过编译,只能被继承。
6.3如果派生合约没有实现抽象函数,则该派生合约也将被标记为抽象合约。
pragma solidity ^0.5.0;
contract ACalculator {
function getResult() public view returns(uint);
}
contract Test is ACalculator {
function getResult() public view returns(uint) {
uint a = 1;
uint b = 2;
uint result = a + b;
return result;
}
}
7 assembly
Inline Assembly是一种以较低级别访问以太坊虚拟机的方法。
address _addr = msg.sender;
uint256 _codeLength;
// 检索code的size
assembly {_codeLength := extcodesize(_addr)}
8 delete
if() throw;
assert、require、revert