Contract Basics
Call Contract
generate contract var
在已知被调用合约的源码(接口)和地址的情况下,可以采取生成合约变量的方式来调用已部署的合约,有以下方式可用用来生成合约变量:
- 传入合约地址: OtherContract(contractAddr).f(p1)或OtherContract(contractAddr).f{value: msg.value}(p1)(调用时发送 eth)
- 传入合约变量: 调用方法定义时声明一个 OtherContract c的参数,在方法体中采用c.f(p1);来调用
- 创建合约变量: 调用方法中 OtherContract o = OtherContract(contractAddr); o.f(p1);
总结:
contractName(contractAddr)来生成合约变量
call
在不知道合约源码或 ABI 的情况下,可以采用 call 来调用其他合约,具体方式如下:
- contractAddr.call(bytecode)
- 
- 其中 bytecode=abi.encodeWithSignature("函数签名", 逗号分隔的参数),函数签名:函数名(逗号分隔的参数类型)
 
- 其中 
- 
- 调用时发送 ETH 及指定 gas: contractAddr.call{value: x, gas: x}(bytecode)
 
- 调用时发送 ETH 及指定 gas: 
delegateCall
deleteCall 的调用方式如下:
- contractAddr.delegateCall(bytecode)
- 
- bytecode = abi.encodeWithSignature("函数签名", 逗号分隔的参数),函数签名为:- 函数名(逗号分隔的参数类型)
 
关系 call 与 delegateCall 的区别详见: ./24061701-delegate_call.md
summary
| 调用合约的方式 | 适应场景 | 语法 | 
|---|---|---|
| 生成合约变量 | 已知合约源码或 ABI | ContractName(contractAddr) | 
| call | 不知道合约与源码及 ABI | contractAddr.call(abi.encodeWithSignature("函数名(逗号分隔的参数类型)", 逗号分隔的参数)) | 
| delegateCall | 不知道合约与源码及 ABI | contractAddr.delegateCall(abi.encodeWithSignature("函数名(逗号分隔的参数类型)", 逗号分隔的参数)) | 
Contract Create And Destory
create contratc
create
在合约中创建新的合约,语法如下:
    ContractName x = new ContractName{value: _value}(params);
说明:
- 如果合约是 payable修饰的,则可以在创建合约时传递 value 值
create2
what is create2
create2 的作用就是能够在合约未部署之前预测合约的地址
why need create2
满足在合约未部署之前,需要事先计算出合约地址的场景
合约地址的计算
| 创建合约方法 | 合约地址计算方法 | 说明 | 
|---|---|---|
| create | contractAddr = hash(creatorAddr, nonce) | creatorAddr: 部署合约的钱包地址或者是合约地址nonce: 创建者地址的 nonce,由于是可变的,且不能准确预测,所以使用create方法创建出来的合约地址,是不可预测的 | 
| create2 | contractAddr = hash("0xFF", creatorAddr, salt, initCode) | 0xFF: 常量,用于区分create方法creatorAddr: 部署合约的钱包或合约地址salt: 一个创建者指定的byte32的值,目的是用来影响创建合约的地址initcode: 新合约的初始字节码(合约的creation code和构造函数的参数) | 
how to use create2
create2 创建合约语法如下:
    ContractName x = new ContractName{salt: _salt, value: _value}(params)
说明:
- salt: 盐值
- value: 如果创建的合约时- payable的,则允许创建时向其转账
- params: 新合约构造函数的参数
destory contract
ABI Encode And Decode
what is ABI
ABI: application binary interface, 应用程序二进制接口,是与合约交互的标准。其数据也是通过了该类型进行编码,由于编码时只包含了数据,在解码时,要申明返回值的类型
ABI encode
| 方法名 | 备注 | 
|---|---|
| abi.encode(a, b, c) | |
| abi.encodePacked() | abi.encode(),只不过会省略多余填充的 0 | 
| abi.encideWithSignature() | abi.encode功能类似,只不过第一个参数为函数签名(functionName(逗号分隔的参数类型)) | 
| abi.encodeWithSelector() | abi.encodeWithSelector类似,只不过第一个参数为函数选择器(bytes4(keccak256(functionName(逗号分隔的参数类型))))abi.encideWithSignature()完全一致 | 
ABI decode
abi.decode 用于解码 abi.encode 编码的二进制数据,将它还原成原本的参数,用法如下:
function decode(bytes memory data) public pure returns(uint dx, address daddr, string memory dname, uint[2] memory darray) {
    (dx, daddr, dname, darray) = abi.decode(data, (uint, address, string, uint[2]));
}
Hash
solidity 中常用的哈希函数是 keccak256,其用法如下:
    hash = keccak256(数据)
keccak256 and sha3
keccak256 与 sha3 的区别和联系:
- 联系: sha3由keccak256标准化而来,很多场景可以同义
- 区别: 在 sha3标准化完成时,更改了其内部算法,导致最终结果与keccak256不一致;以太坊在sha3标准化之前开发出来,所以以太坊的哈希函数是keccak256
Try-Catch
在 solidity 中 try catch 语法,只能用于外部函数或创建合约时 construct 的调用。基本语法如下
    try externalContract.f() returns(returnType val) {
        // call 成功时执行
    } catch {
        // call 失败时执行
    }
备注:
- this.f()也可被视为外部函数调用