restake 2.0.0 → 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 -18
  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,31 +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
- await bee.depositStake(bzz.toString());
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));
66
72
  }
67
73
  else if (cafe_utility_1.Random.chance(1 / 2)) {
68
- await transferBZZ(privateKeys[port - 1633], externalWallet, bzz);
74
+ await runAction(port, `top up postage batch ${postageBatchId}`, () => topup(bee, port));
69
75
  }
70
76
  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);
77
+ await runAction(port, `aid weakest node with ${bzz.toDecimalString()} BZZ`, () => aid(port));
79
78
  }
80
79
  }, sleep, console.error);
81
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
+ }
82
134
  async function transferBZZ(privateKey, targetAddress, amount) {
83
135
  const account = (0, accounts_1.privateKeyToAccount)(ensure0x(privateKey));
84
136
  const client = (0, viem_1.createWalletClient)({
@@ -104,11 +156,12 @@ async function getGasPrice() {
104
156
  return bee_js_1.DAI.fromWei(BigInt(price));
105
157
  }
106
158
  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'] };
159
+ const payload = {
160
+ jsonrpc: '2.0',
161
+ id: 1,
162
+ method: 'eth_getTransactionCount',
163
+ params: [address.toLowerCase(), 'latest']
164
+ };
112
165
  const count = await fetchJsonRpcHexString(payload);
113
166
  return parseInt(count, 16);
114
167
  }
@@ -125,5 +178,16 @@ async function fetchJsonRpcHexString(payload) {
125
178
  function ensure0x(value) {
126
179
  return value.startsWith('0x') ? value : `0x${value}`;
127
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
+ }
128
192
  process.on('unhandledRejection', console.error);
129
193
  process.on('uncaughtException', console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "restake",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "",
5
5
  "bin": {
6
6
  "restake": "./dist/index.js"