1、合约代码
- SimpleAuction.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.0;
contract SimpleAuction {
address payable public beneficiary;
uint public auctionEnd;
address public highestBidder;
uint public highestBid;
mapping(address => uint) pendingReturns;
bool ended;
// 变更触发的事件
event HighestBidIncreased(address bidder, uint amount);
event AuctionEnded(address winner, uint amount);
constructor(uint _biddingTime,address payable _beneficiary) {
beneficiary = _beneficiary;
auctionEnd = block.timestamp + _biddingTime;
}
function bid() public payable {
require(block.timestamp <= auctionEnd);
// 如果出价不够高,返还你的钱
require(msg.value > highestBid);
if (highestBid != 0) {
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
emit HighestBidIncreased(msg.sender, msg.value);
}
/// 取回出价(当该出价已被超越)
function withdraw() public returns (bool) {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
pendingReturns[msg.sender] = 0;
if (!payable(msg.sender).send(amount)) {
// 这里不需抛出异常,只需重置未付款
pendingReturns[msg.sender] = amount;
return false;
}
}
return true;
}
/// 结束拍卖,并把最高的出价发送给受益人
function auctionEnded() public {
// 1. 条件
require(block.timestamp >= auctionEnd, "Auction not yet ended.");
require(!ended, "auctionEnd has already been called.");
// 2. 生效
ended = true;
emit AuctionEnded(highestBidder, highestBid);
// 3. 交互
beneficiary.transfer(highestBid);
}
}
2、合约编译
编译脚本:Compiler.js
const fs = require('fs');
const solc = require('solc');
const { Utils } = require('./utils/utils');
class SOLCompiler {
constructor(path, fileName) {
this.pathFile = `${path}/${fileName}`;
this.config = {
language: 'Solidity',
sources: {
},
settings: { // 自定义编译输出的格式。以下选择输出全部结果。
outputSelection: {
'*': {
'*': ['*']
}
}
},
};
this.fileName = fileName;
}
async writeFile(confData) {
return new Promise((resolve, reject) => {
fs.writeFile(`${this.fileName}.json`, confData, (err) => {
if (err) {
reject(err);
} else {
resolve(true);
}
});
});
}
async compile() {
try {
const content = await Utils.readFile(this.pathFile);
if (!content) {
console.log('文件读取出错');
return;
}
this.config.sources[this.fileName] = {
content: content
};
// 编译得到结果
const compiledOutStr = solc.compile(JSON.stringify(this.config));
const compiledData = JSON.parse(compiledOutStr);
const confData = {
abi: {},
bytecode: ''
};
// output 为json对象,根据json结构保存对应的abi和bytecode
for (let contractName in compiledData.contracts[this.fileName]) {
confData.abi = compiledData.contracts[this.fileName][contractName].abi;
confData.bytecode = compiledData.contracts[this.fileName][contractName].evm.bytecode.object;
}
// console.log(confData);
if (this.writeFile(JSON.stringify(confData))) {
console.log(`compile file: ${this.fileName} is success!`);
}
} catch (e) {
console.log(e.message);
}
}
}
if (process.argv.length > 2) {
const pathFile = process.argv[2];
const pathSplit = pathFile.split('/');
const fileName = pathSplit[pathSplit.length - 1];
const fileNameSplit = fileName.split('.');
const fileExt = fileNameSplit[fileNameSplit.length - 1];
if (fileExt.toLowerCase() != 'sol') {
console.log('请输入正确的文件名');
return;
}
const newPath = pathFile.substring(0, pathFile.length - fileName.length - 1);
console.log(newPath, fileName);
const cc = new SOLCompiler(newPath, fileName);
cc.compile();
// process.exit(0);
} else {
console.log('请输入正确的命令行格式');
}
- 在命令行执行命令
#第一个是编译脚本的位置 ,
#第二个是 .sol 需要编译的源文件的位置
#(因为在文件中使用了自动获取参数的形式,所以需要在命令行指定)
node ./scrips/Compile.js SimpleAuction.sol
3、合约部署
- 部署脚本:deploy_02.js
const Web3 = require('web3');
const fs = require('fs');
const { Console } = require('console');
const web3 = new Web3('http://192.168.75.129:8545');
//通过命令行模式获取文件名作为参数
const fileNameSource_01 = process.argv.splice(2);
const fileNameSource = fileNameSource_01[0];
class Deploy {
async readFile(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, (err, content) => {
if (err) {
reject(err);
} else {
resolve(content);
}
});
});
}
async deploy(filePath) {
const fileContent = await this.readFile(filePath);
// const fileContent = fs.readFileSync(filePath);
if (fileContent) {
const ballotData = JSON.parse(fileContent);
let funDeploy = async () => {
try {
const accounts = await web3.eth.getAccounts();
const account = accounts[0];
console.log(account);
const addr = "0x4e8fe7e83628121a3757ea2f69e8f9cb3aae7123";
const v = 200;
const deployContract = new web3.eth.Contract(ballotData.abi);
const payLaod = {
data: ballotData.bytecode,
arguments: [1000,"0x8f4e1b9f8bfa09b4d4466a2a34237d454b9a2812"]
};
let parameters = {
from: account,
gas: web3.utils.toHex(5000000),
gasPrice: web3.utils.toHex(web3.utils.toWei('30', 'gwei'))
};
const result = await deployContract.deploy(payLaod).send(parameters, (err, txHash) => {
if (!err) {
console.log('Transaction Hash', txHash);
} else {
console.log(err.message);
}
});
console.log('successfully! address : ' + result.options.address);
return result;
} catch (e) {
console.log(e.message);
}
};
await funDeploy();
}
}
}
const filesplitName = fileNameSource.split('.');
const solc_name = filesplitName[filesplitName.length - 1];
if(solc_name.toLowerCase() != 'json'){
Console.log("请输入正确的后缀文件名json");
return;
}else{
new Deploy().deploy(fileNameSource);
}
// new Deploy().deploy("./Faucet.out.json");
//new Deploy().deploy(fileNameSource);
- 在命令行执行命令
#第一个是部署脚本的位置 ,
#第二个是 编译过后得到的 .json 文件的位置
#(因为在文件中使用了自动获取参数的形式,所以需要在命令行指定)
node scripts/deploy_02.js compiled/SimPleAuction.sol.json
4、调用合约
js代码:
/**
* 调用拍卖合约
* 部署后得到的合约hashaddr:// 0xA33636e9A5fBBD0Ab72dA8022bC3557C0406217d
*/
// 引入web3模块
const Web3 = require('web3');
const web3 = new Web3("http://192.168.75.129:8545");
class constracatSimPleAuction{
async constructEg(){
const accounts = await web3.eth.getAccounts();
const _from = accounts[0];
// 创建合约实例
const abi = [{"inputs":[{"internalType":"uint256","name":"_biddingTime","type":"uint256"},{"internalType":"address payable","name":"_beneficiary","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AuctionEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"HighestBidIncreased","type":"event"},{"inputs":[],"name":"auctionEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionEnded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"beneficiary","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"highestBid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"highestBidder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}];
//新版本解锁的方式需要用下面这种方式web3.eth.personal.unlockAccount(地址,密码,解锁时间,回调函数)
web3.eth.personal.unlockAccount(_from,'123456',3600,(err,res)=>{
if(err){
console.log("Err: ",err);
}else{
console.log("Result:",res);
// methodTest(abi, address) {
//交易地址(部署合约返回的):0x8F2093824F3B74f8C0f13cBffcF73B72e1EFF82E
const contractInstance = new web3.eth.Contract(abi, "0x8F2093824F3B74f8C0f13cBffcF73B72e1EFF82E");
//调用合约的bid()方法,send()方法是web3自带的,on后面是固定写法
contractInstance.methods.bid().send({
//bid需要的参数
from: _from,
value:1000
}).on('transactionHash', (hash) => {
console.log(hash);
}).on('confirmation', (confirmationNumber, receipt) => {
}).on('receipt', (receipt) => {
console.log(receipt); //查询这里可以得到结果
}).on('error', console.error);
// }
}
});
// const methed_01 = await contractInstance.bid();
// const methed_02 = await contractInstance.auctionEnded();
// const myEvent = contractInstance.HighestBidIncreased()
}
}
new constracatSimPleAuction().constructEg();
在geth控制台开启挖矿就可以了
#开启挖矿,得到一个块就停止
miner.start(1);admin.sleepBlocks(1);miner.stop()
运行调用合约代码返回的结果