关于合约账户,我有两个疑问:合约账户的创建,只能发生在合约部署时?合约部署,这是一个交易,只能通过一个EOA账户发起?好,先把合约账户创建聊清楚,上面两个问题也就迎刃而解了合约账户创建情况一:普通创建(CREATE指令)由EOA或合约发起的常规部署:newMyContr
关于合约账户,我有两个疑问:
好,先把合约账户创建聊清楚,上面两个问题也就迎刃而解了
由 EOA 或合约 发起的常规部署:
new MyContract(); // Solidity 中部署新合约
🧮 合约地址计算公式:
address = keccak256(rlp_encode([sender_address, sender_nonce]))[12:]
sender_address
: 发起部署的账户(EOA 或合约)sender_nonce
: 当前账户的 nonce(多少个交易或创建合约)keccak256(...)[12:]
: 哈希结果的后 20 字节
就是合约地址假设账户地址是 0xabc...1234
,当前 nonce 是 3,那么合约地址就是:
import { keccak256, RLP, getAddress } from "ethers";
const sender = "0xabc...1234";
const nonce = 3;
// RLP 编码
const rlpEncoded = RLP.encode([sender, nonce]);
// keccak256 哈希并截取后 20 字节
const contractAddress = "0x" + keccak256(rlpEncoded).slice(-40);
通过 CREATE2
指令(通常用于升级代理、账户抽象、工厂模式等):
new MyContract{salt: bytes32(...)}();
🧮 合约地址计算公式(EIP-1014):
address = keccak256(0xFF ++ deployer_address ++ salt ++ keccak256(bytecode))[12:]
deployer_address
: 发起部署的地址salt
: 任意指定的 32 字节keccak256(bytecode)
: 合约初始化代码的哈希0xFF
: 固定前缀,避免冲突💡 重点:CREATE2 允许“预知地址”,甚至还没部署合约前就知道它会在哪里。
场景 | 使用方式 | 地址生成方式 |
---|---|---|
用户钱包部署 一个合约 |
wallet.sendTransaction({data: bytecode}) |
CREATE(EOA 发起) |
工厂合约批量部署 子合约 |
new Child() in Solidity |
CREATE(合约发起) |
升级代理 + CREATE2 部署 | CREATE2 工厂 + salt |
可预测地址 |
ERC-4337 账户抽象钱包部署 | EntryPoint + CREATE2 | 可预测地址(用户注册前就生成) |
✔️ 是的,完全正确。
合约账户的创建本质上就是把代码写入链上,并赋予该地址执行能力。
无论哪种方式,都是部署合约的行为,都会创建一个新的合约账户
不同于 EOA(只需要私钥就能拥有地址),合约账户必须是:
✔️ 不完全正确,精确说法:
内部调用
最后聊一个话题:合约账户属于
合约的部署者吗?
答案是:不属于。它只是由部署者创建,但不归属于部署者
合约部署后,它就成为了链上的一个独立账户,谁都可以跟它交互,部署者也不能“控制”它,除非在合约代码中显式写入权限控制逻辑。
那么如何判断合约的部署者呢?
通常在部署时,把部署者的地址写入合约的状态变量:
contract MyToken {
address public owner;
constructor() {
owner = msg.sender; // msg.sender 就是部署者(EOA)
}
function mint(address to, uint amount) public {
require(msg.sender == owner, "Not owner");
// 进行 mint 逻辑
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!