在以太坊乃至整个Web3的世界里,“钱包”是用户与区块链交互的核心,它不仅用于存储和管理以太坊(ETH)及各类代币,更是用户身份、资产和参与去中心化应用(DApps)的入口,很多人以为“发行钱包”是指像银行一样开立一个账户,但在以太坊的语境下,我们通常指的是创建和部署一个自定义的智能合约钱包,这可以是一个具有特定功能、规则或品牌标识的钱包。
本文将采用手把手的方式,带你一步步了解并实践如何在以太坊上发行一个属于自己的智能合约钱包。
准备工作:在开始之前,你需要什么?
在动手之前,请确保你已经具备以下条件:
- 基础的区块链知识:理解以太坊、智能合约、地址、私钥、Gas等基本概念。
- 编程能力:熟悉Solidity语言(以太坊智能合约编程语言)和JavaScript/TypeScript(用于与合约交互)。
- 开发环境:
- Node.js 和 npm/yarn:用于运行JavaScript环境和包管理。
- VS Code:代码编辑器,推荐安装Solidity相关插件。
- Hardhat 或 Truffle:以太坊开发框架,用于编译、部署和测试智能合约,本文将以Hardhat为例。
- MetaMask:浏览器钱包插件,用于与以太坊网络交互、管理私钥和支付Gas费。
- 测试网络ETH:你需要在以太坊测试网络(如Goerli、Sepolia)中获得一些免费的ETH,用于支付部署合约时的Gas费,你可以从对应的测试网水龙头获取。
第一步:创建一个新的Hardhat项目
-
打开终端,创建一个新的项目目录并进入:
mkdir my-eth-wallet cd my-eth-wallet
-
初始化Hardhat项目:
npx hardhat init
按照提示选择 "Create a basic sample project",并安装依赖。
第二步:编写智能合约钱包代码
Hardhat初始化后会有一个contracts目录,我们在这里创建我们的钱包合约。
-
在
contracts目录下创建一个新文件,例如MyWallet.sol。 -
编写一个简单的钱包合约,这里我们创建一个基础的签名钱包,它允许通过指定所有者来控制资金,并能发送ETH和代币。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**MyWallet
* @dev 一个简单的以太坊智能合约钱包,继承自Ownable,由所有者控制。
*/
contract MyWallet is Ownable {
constructor(address initialOwner) Ownable(initialOwner) {}
/**
* @dev 接收ETH的fallback函数
*/
receive() external payable {}
/**
* @dev 获取合约中存储的ETH余额
* @return 合约的ETH余额(以wei为单位)
*/
function getBalance() public view returns (uint256) {
return address(this).balance;
}
/**
* @dev 发送ETH指定地址
* @param recipient 接收ETH的地址
* @param amount 发送的ETH数量(以wei为单位)
*/
function sendETH(address payable recipient, uint256 amount) public onlyOwner {
require(recipient != address(0), "MyWallet: recipient is the zero address");
require(amount <= getBalance(), "MyWallet: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "MyWallet: ETH transfer failed");
}
/**
* @dev 发送ERC20代币指定地址(需要合约已授权)
* @param tokenAddress ERC20代币的合约地址
* @param recipient 接收代币的地址
* @param amount 发送的代币数量
*/
function sendToken(
address tokenAddress,
address recipient,
uint256 amount
) public onlyOwner {
require(recipient != address(0), "MyWallet: recipient is the zero address");
require(amount > 0, "MyWallet: amount must be greater than zero");
IERC20 token = IERC20(tokenAddress);
require(token.balanceOf(address(this)) >= amount, "MyWallet: insufficient token balance");
bool success = token.transfer(recipient, amount);
require(success, "MyWallet: token transfer failed");
}
}
代码解释:
SPDX-License-Identifier和pragma solidity:许可证和Solidity版本声明。import:导入OpenZeppelin库中的Ownable(所有权管理)和IERC20(ERC20代币接口)合约,使用OpenZeppelin可以避免重复造轮子,提高安全性。contract MyWallet is Ownable:我们的钱包合约继承自Ownable,这意味着合约会有一个所有者(owner),只有所有者才能执行某些关键操作。constructor(address initialOwner)