Skip to content

Commit c4d003c

Browse files
committed
feat: add Mint PoW
1 parent 23a516c commit c4d003c

File tree

3 files changed

+159
-12
lines changed

3 files changed

+159
-12
lines changed

README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,21 @@ Note: Newly created wallets require a transfer of funds
5454
yarn cli mine <tick> --account <address>
5555
```
5656

57+
3. DPoS&PoW mine
5758

59+
```shell
60+
yarn cli mint-pow <workc> --account <address>
61+
```
5862

5963
### Wallet Commands
6064

61-
- View Wallet Info: yarn cli wallet --target <address>
62-
- View information of a specific wallet address.
63-
- View All Wallet Accounts: yarn cli wallet --all
64-
- Display all wallet accounts.
65-
- Create New Wallet Account: yarn cli wallet --create
66-
- Create a new wallet account.
67-
- Set Up Existing Account: yarn cli wallet --set privateKey
68-
- Set up a wallet account that already exists.
65+
- View Wallet Info: `yarn cli wallet --target <address>`
66+
- View All Wallet Accounts: `yarn cli wallet --all`
67+
- Create New Wallet Account: `yarn cli wallet --create`
68+
- Set Up Existing Account: `yarn cli wallet --set privateKey`
6969

7070
### Mining Commands
7171

72-
Start Mining: yarn cli mine <tick> --account <address>
72+
- Start Mining: `yarn cli mine <tick> --account <address>`
7373

74-
- Start mining by specifying the number of ticks and the mining address.
74+
- Start DPoS&PoW Mining: `yarn cli mint-pow <workc> --account <address>`

src/cli.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { program } from "commander";
22
import { runMine } from "./scripts/mine";
33
import { runWallet } from "./scripts/wallet";
4+
import { runMintPow } from "./scripts/mint-pow";
45

56
program
67
.command("wallet")
@@ -15,10 +16,16 @@ program
1516

1617
program
1718
.command("mine <tick>")
18-
.description("Perform Ethernet IERC POW Mining")
19+
.description("Perform Ethereum IERC POW Mining")
1920
.option("-a, --account <account>", "Provide your mining address")
2021
.action((tick, options) => {
2122
runMine(tick, options);
2223
});
23-
24+
program
25+
.command("mint-pow <workc>")
26+
.description("Perform Ethereum IERC DPoS&PoW Mining")
27+
.option("-a, --account <account>", "Provide your mining address")
28+
.action((workc, options) => {
29+
runMintPow(workc, options);
30+
});
2431
program.parse(process.argv);

src/scripts/mint-pow.ts

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { ethers } from "ethers";
2+
import { GAS_PREMIUM, PROVIDER_RPC, ZERO_ADDRESS } from "../constants";
3+
import { DataBase } from "../db";
4+
import { sleep } from "../utils/program";
5+
import { stringToHex } from "../utils/hex";
6+
import Spinnies from "spinnies";
7+
import { printer } from "../utils/log4js";
8+
import { bnUtils } from "../utils/bn";
9+
import { sayMinerLog } from "../utils/prompts";
10+
import dayjs from "dayjs";
11+
import { generateNonce } from "../utils";
12+
13+
interface IMineOptions {
14+
account: string;
15+
}
16+
const tick = "BTCI-POW8";
17+
let unique = 0;
18+
export const runMintPow = async (workc: string, options: IMineOptions) => {
19+
sayMinerLog();
20+
if (!(workc.length >= 6 && workc.length <= 22 && ethers.utils.isHexString(workc))) {
21+
throw new Error("The workc is invalid");
22+
}
23+
const { account } = options;
24+
if (!(await DataBase.miner.exists(`/${account}`))) {
25+
console.log(`
26+
This mining user configuration was not found!
27+
💡 Tips:
28+
1. cli wallet ---set <privateKey> Import the user.
29+
2. cli wallet --all to see configured users
30+
- For more information, use cli help wallet
31+
`);
32+
throw new Error("Mining user configuration not found");
33+
}
34+
35+
printer.trace(`Start mining with ${account}`);
36+
const { privateKey } = await DataBase.miner.getObject<{ privateKey: string }>(`/${account}`);
37+
const provider = new ethers.providers.JsonRpcProvider(PROVIDER_RPC);
38+
const miner = new ethers.Wallet(privateKey, provider);
39+
40+
const [network, currentGasPrice, blockNumber, nonce, balance] = await Promise.all([
41+
provider.getNetwork(),
42+
provider.getGasPrice(),
43+
provider.getBlockNumber(),
44+
miner.getTransactionCount(),
45+
miner.getBalance(),
46+
]);
47+
printer.trace(`network is ${network.name} (chainID: ${network.chainId})`);
48+
const targetGasFee = currentGasPrice.div(100).mul(GAS_PREMIUM);
49+
50+
printer.trace(`Current gas price usage ${bnUtils.fromWei(targetGasFee.toString(), 9)} gwei`);
51+
printer.trace(`nonce is ${nonce}`);
52+
printer.trace(`balance is ${bnUtils.fromWei(balance.toString(), 18).dp(4).toString()}`);
53+
54+
const spinnies = new Spinnies();
55+
printer.trace(`The current mining difficulty is ${workc}`);
56+
printer.trace(`Expected to take 1-2 minutes to calculate...`);
57+
spinnies.add("mining", { text: "start mining...", color: "blue" });
58+
await sleep(1000);
59+
let timer = Date.now(),
60+
startTimer = timer,
61+
mineCount = 0;
62+
63+
while (true) {
64+
mineCount += 1;
65+
const toMintBlockNumber = blockNumber + 5;
66+
const transaction = {
67+
type: 2,
68+
chainId: network.chainId,
69+
to: ZERO_ADDRESS,
70+
maxPriorityFeePerGas: targetGasFee,
71+
maxFeePerGas: targetGasFee,
72+
gasLimit: ethers.BigNumber.from("25000"),
73+
nonce: nonce,
74+
value: ethers.utils.parseEther("0"),
75+
data: stringToHex(
76+
`data:application/json,${JSON.stringify({
77+
p: "ierc-pow",
78+
op: "mint",
79+
tick: tick,
80+
// use_point: '0',
81+
block: String(toMintBlockNumber),
82+
nonce: `${generateNonce()}${unique++}`,
83+
})}`
84+
),
85+
};
86+
const rawTransaction = ethers.utils.serializeTransaction(transaction);
87+
const transactionHash = ethers.utils.keccak256(rawTransaction);
88+
// console.log("🚀 ~ transactionHash:", transactionHash)
89+
90+
const signingKey = miner._signingKey();
91+
const signature = signingKey.signDigest(transactionHash);
92+
// console.log("🚀 ~ signature:", signature)
93+
94+
const recreatedSignature = ethers.utils.joinSignature(signature);
95+
// console.log("🚀 ~ recreatedSignature:", recreatedSignature)
96+
97+
const predictedTransactionHash = ethers.utils.keccak256(
98+
ethers.utils.serializeTransaction(transaction, recreatedSignature)
99+
);
100+
101+
// console.log("🚀 ~ predictedTransactionHash:", predictedTransactionHash)
102+
const now = Date.now();
103+
if (now - timer > 100) {
104+
await sleep(1);
105+
spinnies.update("mining", {
106+
text: `[${dayjs(now).format(
107+
"YYYY-MM-DD HH:mm:ss"
108+
)}] ${mineCount} - ${predictedTransactionHash}`,
109+
color: "red",
110+
});
111+
timer = now;
112+
}
113+
if (predictedTransactionHash.includes(workc)) {
114+
unique = 0;
115+
const currentBlockNumber = await provider.getBlockNumber();
116+
if (Math.abs(currentBlockNumber - toMintBlockNumber) > 5) {
117+
spinnies.fail("mining", {
118+
text: `The block height is too high, please try again later`,
119+
color: "red",
120+
});
121+
return;
122+
}
123+
spinnies.succeed("mining", {
124+
text: `${mineCount} - ${predictedTransactionHash}`,
125+
color: "green",
126+
});
127+
const mineTime = (Date.now() - startTimer) / 1000;
128+
printer.info(
129+
`Total time spent ${mineTime}s, average arithmetic ${Math.ceil(mineCount / mineTime)} c/s`
130+
);
131+
// console.log("🚀 ~ transaction:", transaction)
132+
const realTransaction = await miner.sendTransaction(transaction);
133+
// console.log("🚀 ~ realTransaction:", realTransaction)
134+
printer.info(`mining hash: ${realTransaction.hash}`);
135+
await realTransaction.wait();
136+
137+
return printer.info("mining success");
138+
}
139+
}
140+
};

0 commit comments

Comments
 (0)