contract-wallet Link to heading
- 外部账户(EOA)与 合约账户在 EVM 层面是等效的,都是有:nonce(交
易序号)、balance(余额)、storageRoot(状态)、codeHash(代码)
- 如果该合约可以持有资金、调用任意合约方法,就是一个智能合约钱包账
户
-
智能合约钱包账户:支持多签、multicall、密钥替换、找回
-
AA(ERC4337 / ERC7702): 抽象掉 EOA 与 智能合约钱包账户的区别
example Link to heading
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title ContractWallet - 智能合约钱包
* @dev 一个简单的智能合约钱包实现,支持接收资金和执行任意交易
*/
contract ContractWallet {
// ============ 事件定义 ============
/**
* @dev 存款事件 - 当合约接收到资金时触发
* @param sender 发送者地址
* @param amount 存款金额
* @param balance 存款后合约的总余额
*/
event Deposit(address indexed sender, uint amount, uint balance);
/**
* @dev 执行交易事件 - 当合约执行外部交易时触发
* @param to 目标合约/地址
* @param value 发送的 ETH 数量
* @param data 调用数据(函数调用的编码数据)
*/
event ExecuteTransaction(
address indexed to,
uint value,
bytes data
);
// ============ 状态变量 ============
/**
* @dev 钱包所有者地址
* 只有所有者可以执行交易
*/
address public owner;
// ============ 修饰符 ============
/**
* @dev 只有所有者可以调用的修饰符
* 用于保护关键函数,确保只有钱包所有者能执行操作
*/
modifier onlyOwner() {
require(owner == msg.sender, "not owner");
_; // 继续执行被修饰的函数
}
// ============ 构造函数 ============
/**
* @dev 构造函数 - 部署时设置钱包所有者
* @param _owner 钱包所有者地址
*/
constructor(address _owner) {
owner = _owner;
}
// ============ 接收函数 ============
/**
* @dev receive 函数 - 接收 ETH 转账
* 当有人直接向合约地址转账时自动调用
* external: 只能从外部调用
* payable: 可以接收 ETH
*/
receive() external payable {
// 触发存款事件,记录发送者、金额和合约余额
emit Deposit(msg.sender, msg.value, address(this).balance);
}
// ============ 核心功能函数 ============
/**
* @dev 执行任意交易 - 智能合约钱包的核心功能
* @param _to 目标地址(可以是 EOA 地址或合约地址)
* @param _value 要发送的 ETH 数量(单位:wei)
* @param _data 调用数据(ABI 编码的函数调用数据)
*
* 使用场景:
* 1. 转账 ETH:_to=接收地址, _value=金额, _data=""
* 2. 调用合约:_to=合约地址, _value=0, _data=函数调用编码
* 3. 部署合约:_to=0x0, _value=0, _data=合约字节码
*/
function executeTransaction(
address _to,
uint _value,
bytes memory _data
) public onlyOwner {
// 使用 call 执行低级调用
// {value: _value} 指定发送的 ETH 数量
// _data 是要执行的数据(函数调用或合约创建)
(bool success, ) = _to.call{value: _value}(_data);
// 检查调用是否成功,失败则回滚交易
require(success, "tx failed");
// 触发执行交易事件
emit ExecuteTransaction(_to, _value, _data);
}
}