UINT 是 UINT256的别名
INT是INT256的别名
uint
and int
are aliases for uint256
and int256
, respectively.
Solidity 中整型有明确范围,例如 uint32 的范围是 0 ~ 2**32-1 , 若结果超过范围 会被truncate截断
address 类型 存放一个20字节的以太坊地址
address payable 类似于address ,且提供 transfer 和 send成员 ; 即 普通address默认不能传输ETH , address payable 可以
pragma solidity 0.5.10; contract Test1 { address public notpaybleaddress; address public payableaddress; uint public balance1; uint public balance2; uint public balance3; constructor() public payable { notpaybleaddress = msg.sender; payableaddress=address(0); balance1= address(msg.sender).balance; balance2= address(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2).balance; balance3= address(this).balance; } function test1() public payable { address payable x = address(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2); x.transfer(1 ether); balance1= address(msg.sender).balance; balance2= address(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2).balance; balance3= address(this).balance; } }
ABI 是 Application Binary Interface的简称,即2进制接口。是Ethereum生态中与合约交互的标准接口,包括了 链外和 合约对合约调用。其数据按照类型编码,由于不是自描述的,因此需要对应模式解码。
一个函数调用的调用数据的前4个字节,被用来指定要调用的函数。其是该函数的签名的Keccak-256 (SHA-3)哈希值的前4位。
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
测试代码
pragma solidity 0.5.10; contract Test2 { address public owner; mapping( address => uint ) public balances; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); function transfer(address to,uint256 value) public { balances[to]+= value; balances[address(msg.sender)]-=value; } function _safeTransfer(address token, address to, uint value) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TRANSFER_FAILED'); } function testabitransfer() public { _safeTransfer(address(this),address(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2),100); } constructor() public { owner= msg.sender; balances[msg.sender]=10000; balances[address(this)]=10000; } }
type(C).creationCode
包含协定的创建字节码的内存字节数组。这可以在内联程序集中用于构建自定义创建例程,特别是通过使用 create2 操作码。此属性可以 not 在合同本身或任何派生合同中访问。它使字节码包含在调用站点的字节码中,因此不可能像这样循环引用。
bytes32 public constant INIT_CODE_PAIR_HASH = keccak256(abi.encodePacked(type(PancakePair).creationCode)); function createPair(address tokenA, address tokenB) external returns (address pair) { require(tokenA != tokenB, 'Pancake: IDENTICAL_ADDRESSES'); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'Pancake: ZERO_ADDRESS'); require(getPair[token0][token1] == address(0), 'Pancake: PAIR_EXISTS'); // single check is sufficient bytes memory bytecode = type(PancakePair).creationCode; bytes32 salt = keccak256(abi.encodePacked(token0, token1)); assembly { pair := create2(0, add(bytecode, 32), mload(bytecode), salt) } IPancakePair(pair).initialize(token0, token1); getPair[token0][token1] = pair; getPair[token1][token0] = pair; // populate mapping in the reverse direction allPairs.push(pair); emit PairCreated(token0, token1, pair, allPairs.length); }
create2 参考: https://hackernoon.com/using-ethereums-create2-nw2137q7
关于 memory 和 storage , storage最后都会记录在blockchain上,默认函数里申明的变量 都是memory的, 一般 string 字符串需要 单独申明 memory。
例如 你在函数中特意申明 一个memory变量
uint memory var1=0;
编译器一般会警告:
TypeError: Storage location can only be given for array or struct types. uint memory var1=0; ^————–^
若在contract中的直接定义一个memory 变量 ,则:
uint memory var2=0;
ParserError: Expected identifier but got ‘memory’ uint memory var2=0; ^—-^
若在函数中 一个string 变量未指定为memory ,则会报错:
Warning: Variable is declared as a storage pointer. Use an explicit “storage” keyword to silence this warning. string name1 = name; ^————^
TypeError: Type string memory is not implicitly convertible to expected type string storage pointer. string name1 = name; ^——————-^
所以 一般只需要记录 在函数中的临时 string变量, 要指定要memory。其实也不用特意记住,因为不加memory会报错。
gas 评估 ,在remix 中
(async () => { try { let result = await web3.eth.estimateGas({ to: "0xc4abd0339eb8d57087278718986382264244252f", data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003" }); console.log(result); } catch (e) { console.log(e.message) } })()
在nodejs中:
var Web3 = require('web3'); var web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/260d84d657264ecba48c8d6e95fc707d")); var result = web3.eth.estimateGas({ to: "0xc4abd0339eb8d57087278718986382264244252f", data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003" }); console.log(result);
pure 关键字的函数 效率更高 其暗示这个函数 既不读取 blockchain上的状态 也不修改 状态。
These functions cannot:
Read from state variables – read the block chain
Access balances
Call functions not marked pure
library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } }
view 函数则按时该函数用以读取状态。 这些关键字可以让编译器优化的更好一点。
View functions are read only functions and do not modify the state of the block chain. In other words if you want to read data from the block chain one can use view. Getter method are by default view functions. These functions cannot:
Write to state variables – update the block chain
Emit events
Create contracts or use self destruct
Send ether
参考 https://cryptomarketpool.com/pure-and-view-in-solidity-smart-contracts/
Comment