主要步骤
- 准备: 启动节点 → 连接Web3 → 获取账户
- 编译: 读取源码 → 编译 → 提取ABI和字节码
- 部署: 构造合约 → 估算gas → 发送交易 → 等待确认 → 获取地址
- 初始化: 构造函数执行 → 状态变量设置 → 白名单初始化
- 交互准备: 实例化合约对象 → 测试只读函数
- 用户操作: 注册用户 → 存款ETH → 验证权限
- 权限管理: owner更新白名单 → 用户获得权限
- 状态修改: 用户调用写入函数 → gas消耗 → 状态更新
- 事件处理: 实时监听 → 历史查询 → 日志解析
- 批量操作: 批量更新 → 节省gas
- 错误处理: 捕获异常 → 重试机制 → 用户反馈
- 监控: Gas跟踪 → 事件日志 → 状态变化
MyContract.sol 合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract MyContract {
// 状态变量
address public owner;
uint256 public value;
string public name;
bool public isActive;
// 结构体
struct User {
uint256 id;
string name;
uint256 balance;
uint256 createdAt;
}
// 映射
mapping(address => uint256) public balances;
mapping(address => User) public users;
mapping(address => bool) public whitelist;
// 数组
address[] public userAddresses;
// 事件
event ValueChanged(address indexed changer, uint256 oldValue, uint256 newValue);
event UserRegistered(address indexed user, uint256 userId, string userName);
event FundsDeposited(address indexed from, uint256 amount);
event FundsWithdrawn(address indexed to, uint256 amount);
event WhitelistUpdated(address indexed user, bool status);
// 修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
modifier onlyWhitelisted() {
require(whitelist[msg.sender] || msg.sender == owner, "Not whitelisted");
_;
}
modifier whenActive() {
require(isActive, "Contract is not active");
_;
}
// 构造函数
constructor(string memory _name, uint256 _initialValue) {
owner = msg.sender;
name = _name;
value = _initialValue;
isActive = true;
// 将部署者加入白名单
whitelist[msg.sender] = true;
}
// 1. 读取函数示例
function getContractInfo() public view returns (
address contractOwner,
string memory contractName,
uint256 contractValue,
bool activeStatus,
uint256 userCount
) {
return (owner, name, value, isActive, userAddresses.length);
}
function getUserBalance(address _user) public view returns (uint256) {
return balances[_user];
}
function getAllUsers() public view returns (address[] memory) {
return userAddresses;
}
function calculateWithFee(uint256 _amount) public pure returns (uint256) {
return _amount + (_amount * 5 / 100); // 5% 手续费
}
// 2. 写入函数示例
function setValue(uint256 _newValue) public onlyWhitelisted whenActive {
require(_newValue > 0, "Value must be greater than 0");
uint256 oldValue = value;
value = _newValue;
emit ValueChanged(msg.sender, oldValue, _newValue);
}
function registerUser(string memory _userName) public whenActive returns (uint256) {
require(bytes(_userName).length > 0, "Username cannot be empty");
require(users[msg.sender].id == 0, "User already registered");
uint256 userId = userAddresses.length + 1;
users[msg.sender] = User({
id: userId,
name: _userName,
balance: 0,
createdAt: block.timestamp
});
userAddresses.push(msg.sender);
emit UserRegistered(msg.sender, userId, _userName);
return userId;
}
function deposit() public payable whenActive {
require(msg.value > 0, "Deposit amount must be greater than 0");
balances[msg.sender] += msg.value;
emit FundsDeposited(msg.sender, msg.value);
}
function withdraw(uint256 _amount) public whenActive {
require(balances[msg.sender] >= _amount, "Insufficient balance");
require(_amount > 0, "Amount must be greater than 0");
balances[msg.sender] -= _amount;
// 使用call进行转账(推荐方式)
(bool success, ) = msg.sender.call{value: _amount}("");
require(success, "Transfer failed");
emit FundsWithdrawn(msg.sender, _amount);
}
function transfer(address _to, uint256 _amount) public whenActive {
require(balances[msg.sender] >= _amount, "Insufficient balance");
require(_to != address(0), "Invalid recipient address");
require(_amount > 0, "Amount must be greater than 0");
balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
// 3. 仅owner可调用的函数
function updateWhitelist(address _user, bool _status) public onlyOwner {
whitelist[_user] = _status;
emit WhitelistUpdated(_user, _status);
}
function toggleActive() public onlyOwner {
isActive = !isActive;
}
function changeName(string memory _newName) public onlyOwner {
name = _newName;
}
function withdrawContractBalance() public onlyOwner {
uint256 contractBalance = address(this).balance;
require(contractBalance > 0, "No balance to withdraw");
(bool success, ) = owner.call{value: contractBalance}("");
require(success, "Transfer failed");
}
// 4. 批量操作
function batchUpdateWhitelist(address[] memory _users, bool[] memory _statuses) public onlyOwner {
require(_users.length == _statuses.length, "Arrays length mismatch");
for (uint256 i = 0; i < _users.length; i++) {
whitelist[_users[i]] = _statuses[i];
emit WhitelistUpdated(_users[i], _statuses[i]);
}
}
// 5. 工具函数
function getUserInfo(address _user) public view returns (
uint256 userId,
string memory userName,
uint256 userBalance,
uint256 registrationTime,
bool isWhitelisted
) {
User memory user = users[_user];
return (
user.id,
user.name,
balances[_user],
user.createdAt,
whitelist[_user]
);
}
function getContractBalance() public view returns (uint256) {
return address(this).balance;
}
// 6. 回退函数和接收函数
receive() external payable {
balances[msg.sender] += msg.value;
emit FundsDeposited(msg.sender, msg.value);
}
fallback() external payable {
// 自定义回退逻辑
if (msg.value > 0) {
balances[msg.sender] += msg.value;
emit FundsDeposited(msg.sender, msg.value);
}
}
// 7. 权限转移
function transferOwnership(address _newOwner) public onlyOwner {
require(_newOwner != address(0), "Invalid new owner address");
owner = _newOwner;
}
}
完整的使用示例代码
// myContractInteractions.js
const Web3 = require('web3');
const fs = require('fs');
const solc = require('solc');
// 1. 初始化Web3
const web3 = new Web3('http://localhost:8545');
class MyContractInteractor {
constructor() {
this.contract = null;
this.accounts = [];
this.contractAddress = '';
}
// 2. 编译合约
async compileContract() {
const source = fs.readFileSync('MyContract.sol', 'utf8');
const input = {
language: 'Solidity',
sources: {
'MyContract.sol': {
content: source
}
},
settings: {
outputSelection: {
'*': {
'*': ['abi', 'evm.bytecode']
}
}
}
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
this.abi = output.contracts['MyContract.sol']['MyContract'].abi;
this.bytecode = output.contracts['MyContract.sol']['MyContract'].evm.bytecode.object;
console.log('✅ 合约编译成功');
return { abi: this.abi, bytecode: this.bytecode };
}
// 3. 部署合约
async deployContract() {
try {
this.accounts = await web3.eth.getAccounts();
const contract = new web3.eth.Contract(this.abi);
console.log('🚀 部署合约中...');
const deployedContract = await contract.deploy({
data: '0x' + this.bytecode,
arguments: ['MyFirstContract', 100] // 构造函数参数
})
.send({
from: this.accounts[0],
gas: 3000000,
gasPrice: web3.utils.toWei('20', 'gwei')
});
this.contractAddress = deployedContract.options.address;
this.contract = deployedContract;
console.log(`✅ 合约部署成功,地址: ${this.contractAddress}`);
console.log(`📝 交易哈希: ${deployedContract.transactionHash}`);
return deployedContract;
} catch (error) {
console.error('❌ 部署失败:', error);
throw error;
}
}
// 4. 连接到已部署的合约
async connectToContract(address) {
this.contractAddress = address;
this.contract = new web3.eth.Contract(this.abi, address);
console.log(`✅ 已连接到合约: ${address}`);
return this.contract;
}
// 5. 读取函数示例
async readContractInfo() {
try {
console.log('\n📖 读取合约信息...');
// 读取公共变量
const owner = await this.contract.methods.owner().call();
const contractName = await this.contract.methods.name().call();
const value = await this.contract.methods.value().call();
const isActive = await this.contract.methods.isActive().call();
console.log(`👑 合约所有者: ${owner}`);
console.log(`🏷️ 合约名称: ${contractName}`);
console.log(`💰 当前值: ${value}`);
console.log(`🔌 激活状态: ${isActive}`);
// 调用返回多个值的函数
const info = await this.contract.methods.getContractInfo().call();
console.log(`👥 用户数量: ${info.userCount}`);
// 计算函数
const withFee = await this.contract.methods.calculateWithFee(100).call();
console.log(`🧮 100 + 5%手续费 = ${withFee}`);
return { owner, contractName, value, isActive };
} catch (error) {
console.error('❌ 读取失败:', error);
}
}
// 6. 写入函数示例
async interactWithContract() {
try {
console.log('\n✍️ 与合约交互...');
// 注册用户
console.log('👤 注册用户...');
const tx1 = await this.contract.methods.registerUser("Alice").send({
from: this.accounts[1],
gas: 200000
});
console.log(`✅ 用户注册成功,交易哈希: ${tx1.transactionHash}`);
// 存款
console.log('💰 存款1 ETH...');
const tx2 = await this.contract.methods.deposit().send({
from: this.accounts[1],
value: web3.utils.toWei('1', 'ether'),
gas: 150000
});
console.log(`✅ 存款成功,交易哈希: ${tx2.transactionHash}`);
// 查询余额
const balance = await this.contract.methods.getUserBalance(this.accounts[1]).call();
console.log(`💳 用户余额: ${web3.utils.fromWei(balance, 'ether')} ETH`);
// 转账给其他用户
console.log('🔄 转账给其他用户...');
const tx3 = await this.contract.methods.transfer(this.accounts[2], web3.utils.toWei('0.5', 'ether'))
.send({
from: this.accounts[1],
gas: 150000
});
console.log(`✅ 转账成功,交易哈希: ${tx3.transactionHash}`);
// Owner操作:更新白名单
console.log('📝 更新白名单...');
const tx4 = await this.contract.methods.updateWhitelist(this.accounts[1], true)
.send({
from: this.accounts[0],
gas: 150000
});
console.log(`✅ 白名单更新成功`);
// 设置新值(现在用户在白名单中)
console.log('🔧 设置新值...');
const tx5 = await this.contract.methods.setValue(200)
.send({
from: this.accounts[1],
gas: 150000
});
console.log(`✅ 值更新成功,交易哈希: ${tx5.transactionHash}`);
} catch (error) {
console.error('❌ 交互失败:', error.message);
}
}
// 7. 事件监听
async setupEventListeners() {
console.log('\n👂 设置事件监听器...');
// 监听ValueChanged事件
this.contract.events.ValueChanged({
filter: {},
fromBlock: 0
})
.on('data', (event) => {
console.log(`📊 ValueChanged事件:`);
console.log(` 改变者: ${event.returnValues.changer}`);
console.log(` 旧值: ${event.returnValues.oldValue}`);
console.log(` 新值: ${event.returnValues.newValue}`);
console.log(` 区块: ${event.blockNumber}`);
})
.on('error', console.error);
// 监听UserRegistered事件
this.contract.events.UserRegistered({
filter: {},
fromBlock: 0
})
.on('data', (event) => {
console.log(`👤 UserRegistered事件:`);
console.log(` 用户: ${event.returnValues.user}`);
console.log(` ID: ${event.returnValues.userId}`);
console.log(` 名称: ${event.returnValues.userName}`);
});
// 监听所有事件
this.contract.events.allEvents({
fromBlock: 'latest'
})
.on('data', (event) => {
console.log(`📨 收到事件: ${event.event} from ${event.returnValues}`);
});
}
// 8. 批量操作示例
async batchOperations() {
console.log('\n🔄 批量操作示例...');
try {
// 批量更新白名单
const users = [this.accounts[2], this.accounts[3]];
const statuses = [true, true];
const tx = await this.contract.methods
.batchUpdateWhitelist(users, statuses)
.send({
from: this.accounts[0],
gas: 300000
});
console.log(`✅ 批量操作成功,交易哈希: ${tx.transactionHash}`);
} catch (error) {
console.error('❌ 批量操作失败:', error);
}
}
// 9. 查询历史事件
async queryPastEvents() {
try {
console.log('\n📜 查询历史事件...');
const events = await this.contract.getPastEvents('ValueChanged', {
fromBlock: 0,
toBlock: 'latest'
});
console.log(`📊 找到 ${events.length} 个ValueChanged事件`);
events.forEach((event, index) => {
console.log(` ${index + 1}. ${event.returnValues.changer} 从 ${event.returnValues.oldValue} 改为 ${event.returnValues.newValue}`);
});
return events;
} catch (error) {
console.error('❌ 查询事件失败:', error);
}
}
// 10. 完整的交互流程
async fullInteraction() {
try {
// 编译合约
await this.compileContract();
// 部署或连接
const useExisting = false; // 设为true使用已部署合约
const existingAddress = '0x...'; // 已部署合约地址
if (!useExisting) {
await this.deployContract();
} else {
await this.connectToContract(existingAddress);
}
// 获取账户
this.accounts = await web3.eth.getAccounts();
console.log(`👥 可用账户: ${this.accounts.slice(0, 3).join(', ')}...`);
// 读取合约信息
await this.readContractInfo();
// 设置事件监听
await this.setupEventListeners();
// 与合约交互
await this.interactWithContract();
// 批量操作
await this.batchOperations();
// 查询历史事件
await this.queryPastEvents();
console.log('\n🎉 所有操作完成!');
} catch (error) {
console.error('❌ 流程执行失败:', error);
}
}
}
// 使用示例
async function main() {
const interactor = new MyContractInteractor();
// 运行完整流程
await interactor.fullInteraction();
// 或单独调用某个功能
// await interactor.compileContract();
// await interactor.deployContract();
// await interactor.connectToContract('0x...');
// await interactor.readContractInfo();
}
// 运行主函数
if (require.main === module) {
main().catch(console.error);
}
module.exports = MyContractInteractor;
package.json 依赖
{
"name": "my-contract-interaction",
"version": "1.0.0",
"scripts": {
"start": "node myContractInteractions.js",
"deploy": "node deploy.js",
"test": "node testInteractions.js"
},
"dependencies": {
"web3": "^4.0.3",
"solc": "^0.8.19",
"dotenv": "^16.0.0"
}
}
测试脚本示例
// testInteractions.js
const MyContractInteractor = require('./myContractInteractions.js');
async function test() {
const interactor = new MyContractInteractor();
// 测试编译
await interactor.compileContract();
// 测试部署(需要本地以太坊节点)
if (process.env.TEST_DEPLOY === 'true') {
await interactor.deployContract();
await interactor.readContractInfo();
}
console.log('✅ 测试完成');
}
test();
这个完整的示例包含了:
- 全面的 Solidity 合约:包含各种函数类型、修饰器、事件、数据结构
- 完整的 Web3.js 交互流程:编译、部署、读取、写入、事件监听
- 错误处理和最佳实践
- 模块化设计:便于扩展和维护
188

被折叠的 条评论
为什么被折叠?



