restake 2.0.1 → 2.1.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.
Files changed (2) hide show
  1. package/dist/index.js +82 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -29,6 +29,9 @@ const postageBatchId = cafe_utility_1.Arrays.requireStringArgument(process_1.arg
29
29
  const externalWallet = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'external-wallet');
30
30
  const privateKeysPath = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'private-keys-path');
31
31
  const jsonRpcUrl = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'json-rpc-url');
32
+ const telegramToken = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'telegram-token');
33
+ const telegramChatId = cafe_utility_1.Arrays.requireStringArgument(process_1.argv, 'telegram-chat-id');
34
+ const BASE_PORT = 1633;
32
35
  const privateKeys = (0, fs_1.readFileSync)(privateKeysPath, 'utf-8').split('\n').filter(Boolean);
33
36
  if (n !== privateKeys.length) {
34
37
  console.error(`Expected ${n} private keys, but got ${privateKeys.length}`);
@@ -42,7 +45,7 @@ async function main() {
42
45
  async function validatePrivateKeys() {
43
46
  for (let i = 0; i < n; i++) {
44
47
  const privateKey = privateKeys[i];
45
- const port = 1633 + i;
48
+ const port = BASE_PORT + i;
46
49
  const bee = new bee_js_1.Bee(`http://localhost:${port}`);
47
50
  const addresses = await bee.getNodeAddresses();
48
51
  const address = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKey)).address;
@@ -54,34 +57,80 @@ async function validatePrivateKeys() {
54
57
  }
55
58
  function runLoop() {
56
59
  cafe_utility_1.System.forever(async () => {
57
- const port = 1633 + cafe_utility_1.Random.intBetween(0, n - 1);
60
+ const port = BASE_PORT + cafe_utility_1.Random.intBetween(0, n - 1);
58
61
  const bee = new bee_js_1.Bee(`http://localhost:${port}`);
59
62
  const wallet = await bee.getWalletBalance();
60
63
  if (wallet.bzzBalance.lt(bzz)) {
61
64
  console.log(`:${port} balance is ${wallet.bzzBalance.toDecimalString()} BZZ, skipping`);
62
65
  return;
63
66
  }
64
- if (cafe_utility_1.Random.chance(1 / 3)) {
65
- console.log(`:${port} depositing ${bzz.toDecimalString()} BZZ as stake`);
66
- await bee.depositStake(bzz);
67
+ if (cafe_utility_1.Random.chance(1 / 4)) {
68
+ await runAction(port, `stake ${bzz.toDecimalString()} BZZ`, () => stake(bee, port));
69
+ }
70
+ else if (cafe_utility_1.Random.chance(1 / 3)) {
71
+ await runAction(port, `transfer ${bzz.toDecimalString()} BZZ to external wallet`, () => transfer(port));
67
72
  }
68
73
  else if (cafe_utility_1.Random.chance(1 / 2)) {
69
- console.log(`:${port} transferring ${bzz.toDecimalString()} BZZ to external wallet`);
70
- await transferBZZ(privateKeys[port - 1633], externalWallet, bzz);
74
+ await runAction(port, `top up postage batch ${postageBatchId}`, () => topup(bee, port));
71
75
  }
72
76
  else {
73
- const postageBatches = await bee.getGlobalPostageBatches();
74
- const postageBatch = postageBatches.find(batch => batch.batchID.toString() === postageBatchId);
75
- if (!postageBatch) {
76
- console.error(`Postage batch with ID ${postageBatchId} not found`);
77
- return;
78
- }
79
- const { amount } = await bee.calculateTopUpForBzz(postageBatch.depth, bzz);
80
- console.log(`:${port} topping up postage batch ${postageBatchId} with ${amount} amount`);
81
- await bee.topUpBatch(postageBatch.batchID, amount);
77
+ await runAction(port, `aid weakest node with ${bzz.toDecimalString()} BZZ`, () => aid(port));
82
78
  }
83
79
  }, sleep, console.error);
84
80
  }
81
+ async function runAction(port, description, action) {
82
+ try {
83
+ await action();
84
+ await sendTelegramMessage(`Port ${port}: ${description} succeeded`);
85
+ }
86
+ catch (error) {
87
+ await sendTelegramMessage(`Port ${port}: ${description} failed: ${error}`);
88
+ }
89
+ }
90
+ async function stake(bee, port) {
91
+ console.log(`:${port} depositing ${bzz.toDecimalString()} BZZ as stake`);
92
+ await bee.depositStake(bzz);
93
+ }
94
+ async function transfer(port) {
95
+ console.log(`:${port} transferring ${bzz.toDecimalString()} BZZ to external wallet`);
96
+ await transferBZZ(privateKeys[port - BASE_PORT], externalWallet, bzz);
97
+ }
98
+ async function topup(bee, port) {
99
+ const postageBatches = await bee.getGlobalPostageBatches();
100
+ const postageBatch = postageBatches.find(batch => batch.batchID.toString() === postageBatchId);
101
+ if (!postageBatch) {
102
+ console.error(`Postage batch with ID ${postageBatchId} not found`);
103
+ return;
104
+ }
105
+ const { amount } = await bee.calculateTopUpForBzz(postageBatch.depth, bzz);
106
+ console.log(`:${port} topping up postage batch ${postageBatchId} with ${amount} amount`);
107
+ await bee.topUpBatch(postageBatch.batchID, amount);
108
+ }
109
+ async function aid(port) {
110
+ const weakestAddress = await findWeakestNodeAddress();
111
+ const currentAddress = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKeys[port - BASE_PORT])).address;
112
+ if (weakestAddress && weakestAddress.toLowerCase() !== currentAddress.toLowerCase()) {
113
+ console.log(`:${port} aiding weakest node ${weakestAddress} with ${bzz.toDecimalString()} BZZ`);
114
+ await transferBZZ(privateKeys[port - BASE_PORT], weakestAddress, bzz);
115
+ }
116
+ else {
117
+ console.log(`:${port} weakest node is self, skipping aid`);
118
+ }
119
+ }
120
+ async function findWeakestNodeAddress() {
121
+ let minStake = null;
122
+ let weakestAddress = null;
123
+ for (let i = 0; i < n; i++) {
124
+ const port = BASE_PORT + i;
125
+ const bee = new bee_js_1.Bee(`http://localhost:${port}`);
126
+ const stake = await bee.getStake();
127
+ if (minStake === null || stake.lt(minStake)) {
128
+ minStake = stake;
129
+ weakestAddress = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKeys[i])).address;
130
+ }
131
+ }
132
+ return weakestAddress;
133
+ }
85
134
  async function transferBZZ(privateKey, targetAddress, amount) {
86
135
  const account = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKey));
87
136
  const client = (0, viem_1.createWalletClient)({
@@ -107,11 +156,12 @@ async function getGasPrice() {
107
156
  return bee_js_1.DAI.fromWei(BigInt(price));
108
157
  }
109
158
  async function getTransactionCount(address) {
110
- address = address.toLowerCase();
111
- if (address.startsWith('0x')) {
112
- address = address.slice(2);
113
- }
114
- const payload = { jsonrpc: '2.0', id: 1, method: 'eth_getTransactionCount', params: [`0x${address}`, 'latest'] };
159
+ const payload = {
160
+ jsonrpc: '2.0',
161
+ id: 1,
162
+ method: 'eth_getTransactionCount',
163
+ params: [address.toLowerCase(), 'latest']
164
+ };
115
165
  const count = await fetchJsonRpcHexString(payload);
116
166
  return parseInt(count, 16);
117
167
  }
@@ -128,5 +178,16 @@ async function fetchJsonRpcHexString(payload) {
128
178
  function ensure0x(value) {
129
179
  return value.startsWith('0x') ? value : `0x${value}`;
130
180
  }
181
+ async function sendTelegramMessage(text) {
182
+ console.log('Sending Telegram message:', text);
183
+ await fetch(`https://api.telegram.org/bot${telegramToken}/sendMessage`, {
184
+ method: 'POST',
185
+ headers: { 'Content-Type': 'application/json' },
186
+ body: JSON.stringify({ chat_id: telegramChatId, text }),
187
+ signal: AbortSignal.timeout(cafe_utility_1.Dates.seconds(10))
188
+ }).catch(error => {
189
+ console.error('Failed to send Telegram message:', error);
190
+ });
191
+ }
131
192
  process.on('unhandledRejection', console.error);
132
193
  process.on('uncaughtException', console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "restake",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "restake": "./dist/index.js"