🗒️Solidity易混点
type
status
date
slug
summary
tags
category
icon
password
✅初学solidity容易混淆的一些小点,简单记录,方便回顾。
可见性:
- public
从合约(外+内)调用
自动创建getter函数,如:
- external
(外)
- internal
(内+子孙)
- private
(内)
函数修饰符
- view
函数只可读,不能修改状态变量
- pure
不读不写
- payable
可以接收以太币的函数
状态变量修饰符
- Immutable、constant
声明不可变的状态变量。
immutable:合约部署时初始化,后续一旦设置,就不能被改变。
constant:编译时即已知的常量。
- calldata、memory、storage
storage:状态变量。永久存储在区块链上,函数外声明的变量都是storage。花销较大,命名时可以加上前缀“s_”,这样在优化gas时容易注意到。
memory:函数参数,内部变量。大多数默认memory(string需要指定memory或calldata)。
calldata:只读的临时变量。只能用于外部(external)函数的参数。
return关键字
函数中为return,函数声明时为returns
return的两者写法:
receive()、fallback():
都没有
function
关键字。因为是特殊的函数(如 constructor
)。必须是
external payable
,不能接收参数,也不返回内容。
注:什么时候为fallback():
- 当调用不存在的函数
- msg.data不为空
- msg.data为空,但receive()不存在
1e18 wei
1e18 = 1 ETH = 1 *10 **18 = 1000000000000000000
先乘后除
solidity没有浮点数,所以除以计算时需要乘上除数,且除数在后,精度更高。
transfer,send,call
- transfer:对当前账户转账。最多只能2300gas,超过会revert。
- send:最多只能2300gas,但超过不会revert,会返回布尔值。
- call:没有gas limit,不用ABI。返回两个变量:一个表示成功或失败的布尔值,一个存储返回数据(如果有)的字节对象。
msg.***
msg.value:发送到合约的以太币数量。
库(library)
库(library)在Solidity中是一种特殊类型的合约,具有以下特点:
- 库的代码可以被包含并在其他合约中重复使用,而无需部署库本身。
- 库中的函数可以是内部函数(
internal
),这意味着这些函数在编译时被直接嵌入调用它们的合约中。
- 库不能拥有状态变量或发送和接收以太币,这增加了其安全性和可预测性。
举例:
注:why not interface:
接口(interface)在Solidity中用于定义合约的标准,它们只包含函数声明,没有具体实现。接口通常用于定义某种合约必须实现的功能,以便于合约之间的互操作性。
动态数组自带函数
push()
: 向数组末尾添加一个新元素。
pop()
:从数组末尾移除并返回最后一个元素。
length
:返回数组的当前长度(元素个数)。
delete
:删除指定索引的元素,将其设置为默认值。内置全局变量
msg.sender:返回当前调用合约的地址。
msg.value:返回当前调用合约时附带的以太币数量(单位是 wei)。
msg.data:返回当前调用的原始数据(包含函数选择器和编码参数)。
tx.origin:返回最初发起交易的地址(可能是用户钱包地址)。
block.number:返回当前区块的区块号。
block.timestamp:返回当前区块的时间戳(从 1970 年 1 月 1 日开始的秒数)。
block.difficulty:返回当前区块的难度。
block.coinbase:返回当前区块的矿工地址(coinbase 地址)。
gasleft():返回当前合约调用中剩余的 gas 数量。
内置函数
- assert(条件):
验证条件是否为真,如果不为真,交易会被回滚,并且消耗的 gas 会被丢弃。
- require(条件,”错误消息”):
验证条件是否为真,如果不为真,交易会被回滚,并且可以指定错误消息。
- revert(“错误消息”):
手动回滚交易,并可以提供错误消息。
- payable(地址).transfer(金额):
将指定金额的以太币从当前合约发送到目标地址(注意:在 Solidity 0.8.0 及以上版本,建议使用
.call
代替 transfer
)。- payable(地址).send(金额):
将指定金额的以太币从当前合约发送到目标地址,并返回布尔值以指示是否成功(注意:在 Solidity 0.8.0 及以上版本,建议使用
.call
代替 send
)。- call():
用于调用其他合约的函数或发送以太币。它可以接收以太币并返回调用结果的布尔值。例:
- keccak256()
计算输入数据的Keccak-256哈希值。用于确保数据完整性和生成唯一标识符。
代码布局建议
重写、重载
重写:子类重新写父类的函数。子类override,父类virtual。
重载:函数同名,参数不同。
override、virtual
子类合约若要重写函数,要加上override,父类函数要加上virtual。
抽象合约(abstract)
抽象合约里的函数用
virtual
关键字标记,只定义,不实现。它们在子合约中被重写。抽象合约主要用于定义接口和规则,而具体的实现交由继承它的合约来完成。事件(event)
在区块链上创建和触发事件,使得外部应用程序可以监听这些事件,并对事件的发生做出反应。
- 事件声明 (
event
):定义一个事件,用于记录特定操作的发生。
indexed
将event的参数标记为可索引,这样可以更高效地搜索事件。- 触发事件 (
emit
):当特定操作发生时触发事件,将事件记录到区块链日志中。
注:什么时候使用事件:
①当你需要向外部世界通知合约内的状态变化时。
②在需要持久记录某些重要操作的情况。日志可以在链上查询,用于审计和跟踪。
③需要外部应用程序对某些操作做出反应时。外部应用程序无法直接监听合约内部的函数调用,但可以监听事件。
字符串拼接
Solidity中,
string
字符串不能直接用“+”拼接,而是用abi.encodePacked()
进行拼接。abi.encodePacked()
将输入的多个参数编码为字节数组(bytes
),在处理多个 string
或其他类型时,它能高效地将它们拼接在一起。abi编码
- abi.encode()和abi.encodePacked()区别
- abi.encode()
返回一个完整的ABI编码的字节数组,包含了每个参数的类型信息。
如:
// 长度
0x0000000000000000000000000000000000000000000000000000000000000004
// UTF-8编码
0x74657374
- abi.encodePacked()
返回一个压缩的字节数组,没有类型信息,适合用于哈希或唯一标识符生成。
- abi.decode(bytes memory data, (type1, type2, ...));
用于将字节数组解码为原始数据类型。
data
:要解码的字节数组。
(type1, type2, ...)
:要解码到的类型的元组。
编码后得到字节数组,粘贴到解码处,得到原数据:

super.***
当继承的多个父类中有同名的函数,而需要调用其中一个时,直接用
super.***
就可以了。(单个继承也能用)
函数修饰器(modifier)
在函数执行前后插入逻辑,从而实现访问控制、输入验证和状态检查等功能。
用
_;
来表示被修饰的函数的执行位置。索引(indexed)
indexed
关键字用于事件的参数中,表示该事件的参数将被索引。任何人都可以通过区块链的事件日志接口查询日志,标记为indexed
的参数可以在事件查询中作为过滤条件,更高效地搜索和过滤事件。
在事件定义中,最多可以有 三个indexed
参数。这些参数被索引后,可以通过区块链API(如web3.js
、ethers.js
)进行高效的查询和检索。虽然
indexed
参数在查询中提供了便利,但它会略微增加日志的存储成本,因此应当只对需要频繁查询或过滤的参数使用。举例:
from
和to
参数被标记为indexed
,可以通过用户地址来过滤所有转账事件,找出某个用户发送或接收的所有转账。
amount
没有被索引,这意味着无法直接按金额来过滤事件,但可以通过事件触发后获得该信息。
接口(interface)
只声明,没有具体实现。
在合约与外部合约或标准协议交互时,声明接口是最佳实践。
接口使得不同合约之间能够通过相同的函数接口进行通信,而不必关心具体的合约实现。
transfer和transferfrom区别
都用于处理代币转移,主要用于 ERC-20 标准的代币合约。
一、transfer(接收地址,代币数量)
直接转移调用者的代币。
recipient
: 接收代币的目标地址。
amount
: 要转移的代币数量。
二、transferfrom(发送地址,接收地址,代币数量)
代表被授权账户转移其代币。
sender
: 代币的所有者,即代币将从哪个账户中转移。
recipient
: 接收代币的目标地址。
amount
: 要转移的代币数量。
使用
transferFrom
,代币所有者需要先使用 approve
函数,允许某个账户(通常是合约)可以代表自己转移一定数量的代币:汇编代码(Assembly code)
汇编代码是一种直接与 EVM 交互的低级代码,适合对性能要求高的场景或需要直接操作 EVM 内部功能的情况。
上一篇
GOGO 房地产
下一篇
Foundry框架学习
Loading...