restake 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +121 -5
- package/package.json +4 -2
- package/tsconfig.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,129 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const bee_js_1 = require("@ethersphere/bee-js");
|
|
4
5
|
const cafe_utility_1 = require("cafe-utility");
|
|
6
|
+
const fs_1 = require("fs");
|
|
5
7
|
const process_1 = require("process");
|
|
8
|
+
const viem_1 = require("viem");
|
|
9
|
+
const accounts_1 = require("viem/accounts");
|
|
10
|
+
const chains_1 = require("viem/chains");
|
|
11
|
+
const abi = [
|
|
12
|
+
{
|
|
13
|
+
constant: false,
|
|
14
|
+
inputs: [
|
|
15
|
+
{ name: 'recipient', type: 'address' },
|
|
16
|
+
{ name: 'amount', type: 'uint256' }
|
|
17
|
+
],
|
|
18
|
+
name: 'transfer',
|
|
19
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
20
|
+
payable: false,
|
|
21
|
+
stateMutability: 'nonpayable',
|
|
22
|
+
type: 'function'
|
|
23
|
+
}
|
|
24
|
+
];
|
|
6
25
|
const n = cafe_utility_1.Arrays.requireNumberArgument(process_1.argv, 'n');
|
|
7
|
-
const bzz =
|
|
26
|
+
const bzz = bee_js_1.BZZ.fromFloat(cafe_utility_1.Arrays.requireNumberArgument(process_1.argv, 'bzz'));
|
|
8
27
|
const sleep = cafe_utility_1.Dates.make(cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'sleep'));
|
|
9
|
-
cafe_utility_1.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
const postageBatchId = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'postage-batch-id');
|
|
29
|
+
const externalWallet = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'external-wallet');
|
|
30
|
+
const privateKeysPath = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'private-keys-path');
|
|
31
|
+
const jsonRpcUrl = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'json-rpc-url');
|
|
32
|
+
const privateKeys = (0, fs_1.readFileSync)(privateKeysPath, 'utf-8').split('\n').filter(Boolean);
|
|
33
|
+
if (n !== privateKeys.length) {
|
|
34
|
+
console.error(`Expected ${n} private keys, but got ${privateKeys.length}`);
|
|
35
|
+
(0, process_1.exit)(1);
|
|
36
|
+
}
|
|
37
|
+
main();
|
|
38
|
+
async function main() {
|
|
39
|
+
await validatePrivateKeys();
|
|
40
|
+
runLoop();
|
|
41
|
+
}
|
|
42
|
+
async function validatePrivateKeys() {
|
|
43
|
+
for (let i = 0; i < n; i++) {
|
|
44
|
+
const privateKey = privateKeys[i];
|
|
45
|
+
const port = 1633 + i;
|
|
46
|
+
const bee = new bee_js_1.Bee(`http://localhost:${port}`);
|
|
47
|
+
const addresses = await bee.getNodeAddresses();
|
|
48
|
+
const address = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKey)).address;
|
|
49
|
+
if (!addresses.ethereum.equals(address)) {
|
|
50
|
+
console.error(`Private key for port ${port} does not match node's Ethereum address`);
|
|
51
|
+
(0, process_1.exit)(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function runLoop() {
|
|
56
|
+
cafe_utility_1.System.forever(async () => {
|
|
57
|
+
const port = 1633 + cafe_utility_1.Random.intBetween(0, n - 1);
|
|
58
|
+
const bee = new bee_js_1.Bee(`http://localhost:${port}`);
|
|
59
|
+
const wallet = await bee.getWalletBalance();
|
|
60
|
+
if (wallet.bzzBalance.lt(bzz)) {
|
|
61
|
+
console.log(`:${port} balance is ${wallet.bzzBalance.toDecimalString()} BZZ, skipping`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (cafe_utility_1.Random.chance(1 / 3)) {
|
|
65
|
+
await bee.depositStake(bzz.toString());
|
|
66
|
+
}
|
|
67
|
+
else if (cafe_utility_1.Random.chance(1 / 2)) {
|
|
68
|
+
await transferBZZ(privateKeys[port - 1633], externalWallet, bzz);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const postageBatches = await bee.getGlobalPostageBatches();
|
|
72
|
+
const postageBatch = postageBatches.find(batch => batch.batchID.toString() === postageBatchId);
|
|
73
|
+
if (!postageBatch) {
|
|
74
|
+
console.error(`Postage batch with ID ${postageBatchId} not found`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const { amount } = await bee.calculateTopUpForBzz(postageBatch.depth, bzz);
|
|
78
|
+
await bee.topUpBatch(postageBatch.batchID, amount);
|
|
79
|
+
}
|
|
80
|
+
}, sleep, console.error);
|
|
81
|
+
}
|
|
82
|
+
async function transferBZZ(privateKey, targetAddress, amount) {
|
|
83
|
+
const account = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKey));
|
|
84
|
+
const client = (0, viem_1.createWalletClient)({
|
|
85
|
+
chain: chains_1.gnosis,
|
|
86
|
+
transport: (0, viem_1.http)(jsonRpcUrl)
|
|
87
|
+
});
|
|
88
|
+
await client.writeContract({
|
|
89
|
+
account,
|
|
90
|
+
abi,
|
|
91
|
+
address: '0xdbf3ea6f5bee45c02255b2c26a16f300502f68da',
|
|
92
|
+
functionName: 'transfer',
|
|
93
|
+
args: [targetAddress, amount.toPLURBigInt()],
|
|
94
|
+
gas: 100000n,
|
|
95
|
+
gasPrice: (await getGasPrice()).toWeiBigInt(),
|
|
96
|
+
type: 'legacy',
|
|
97
|
+
chain: chains_1.gnosis,
|
|
98
|
+
nonce: await getTransactionCount(account.address)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function getGasPrice() {
|
|
102
|
+
const payload = { jsonrpc: '2.0', id: 1, method: 'eth_gasPrice', params: [] };
|
|
103
|
+
const price = await fetchJsonRpcHexString(payload);
|
|
104
|
+
return bee_js_1.DAI.fromWei(BigInt(price));
|
|
105
|
+
}
|
|
106
|
+
async function getTransactionCount(address) {
|
|
107
|
+
address = address.toLowerCase();
|
|
108
|
+
if (address.startsWith('0x')) {
|
|
109
|
+
address = address.slice(2);
|
|
110
|
+
}
|
|
111
|
+
const payload = { jsonrpc: '2.0', id: 1, method: 'eth_getTransactionCount', params: [`0x${address}`, 'latest'] };
|
|
112
|
+
const count = await fetchJsonRpcHexString(payload);
|
|
113
|
+
return parseInt(count, 16);
|
|
114
|
+
}
|
|
115
|
+
async function fetchJsonRpcHexString(payload) {
|
|
116
|
+
const response = await fetch(jsonRpcUrl, {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: { 'Content-Type': 'application/json' },
|
|
119
|
+
body: JSON.stringify(payload)
|
|
120
|
+
});
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
const object = cafe_utility_1.Types.asObject(data);
|
|
123
|
+
return cafe_utility_1.Types.asHexString(object.result, { strictPrefix: true, uneven: true });
|
|
124
|
+
}
|
|
125
|
+
function ensure0x(value) {
|
|
126
|
+
return value.startsWith('0x') ? value : `0x${value}`;
|
|
127
|
+
}
|
|
13
128
|
process.on('unhandledRejection', console.error);
|
|
129
|
+
process.on('uncaughtException', console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "restake",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"bin": {
|
|
6
6
|
"restake": "./dist/index.js"
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
"license": "ISC",
|
|
15
15
|
"type": "commonjs",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"
|
|
17
|
+
"@ethersphere/bee-js": "^12.1.0",
|
|
18
|
+
"cafe-utility": "^33.8.0",
|
|
19
|
+
"viem": "^2.48.4"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@types/node": "^25.5.2"
|