-
Notifications
You must be signed in to change notification settings - Fork 3
/
topup.js
237 lines (204 loc) · 7.84 KB
/
topup.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
const xrpl = require('xrpl')
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
const { exit } = require('process');
const readline = require("readline");
const client = new xrpl.Client('wss://xahau.network');
const codec = require('ripple-binary-codec');
const hosts_accounts = []
const getServerInfoOnce = (function() {
let serverInfo = null; // Closure to store the server info
let fetchingPromise = null; // Closure to store the promise while fetching
return async function() {
if (!serverInfo && !fetchingPromise) {
fetchingPromise = client.request({
"id": 2,
"command": "server_state",
"ledger_index": "current"
}).then(info => {
serverInfo = info;
fetchingPromise = null; // Reset the promise after fetching
return serverInfo;
});
}
return fetchingPromise || Promise.resolve(serverInfo);
};
})();
async function getXahauBalance(account) {
const server_state = await getServerInfoOnce();
const response = await client.request({
"command": "account_info",
"account": account,
"ledger_index": "validated"
})
const owner_count = response.result.account_data.OwnerCount;
const balance = response.result.account_data.Balance;
const reserve_base = server_state.result.state.validated_ledger.reserve_base;
const reserve_inc = server_state.result.state.validated_ledger.reserve_inc;
const available_balance = balance - (reserve_base + owner_count * reserve_inc);
return (available_balance / 1000000).toFixed(3);
}
async function getFee(account, amount, destination) {
//Dummy payment tx
var payment = await client.autofill({
TransactionType: "Payment",
Account: account,
Amount: xrpl.xrpToDrops(amount),
Destination: destination,
Fee : '0',
SigningPubKey : '0'
});
var txBlob = codec.encode(payment);
const response = await client.request({
"command": "fee",
"tx_blob": txBlob
})
return (parseInt(response.result.drops.base_fee) + 20).toString();
}
async function sendXahau(wallet,domain,destination,amount, retry) {
console.log('\n' + (retry < 3 ? '[retry]':'') + 'Trying to send ' + amount + ' XAH to:' + domain + '[' + destination + ']');
//Calculate expected fee
var fee = await getFee(wallet.address, amount, destination);
//Prepare TX
var payment = await client.autofill({
TransactionType: "Payment",
Account: wallet.address,
Amount: xrpl.xrpToDrops(amount),
Destination: destination,
Fee : fee
});
//Sign and submit
const max_ledger = payment.LastLedgerSequence;
var signed = await wallet.sign(payment);
var tx = await client.submitAndWait(signed.tx_blob);
let txResult = tx.result.meta.TransactionResult
return tx.result.meta.TransactionResult;
}
const main = async () => {
//Get Domain from user
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var domain = "_"
rl.question('Please input your hosts domain or email:', (answer) => {
domain = answer;
});
while (domain == "_") { await new Promise(r => setTimeout(r, 100)) }
var isEmail = domain.includes('@');
if(isEmail)
console.log('\n\nEmail: ' + domain);
else
console.log('\n\nDomain: ' + domain);
//Connect to Xahau
console.log('\n\nConnection to Xahau...');
await client.connect();
//Get hosts from Evernode Registry
var hosts;
try {
console.log('\n\nGetting Evernode hosts from registry, Please wait...');
fetch_url = isEmail ? "https://api.evernode.network/registry/hostsemail/" : "https://api.evernode.network/registry/hosts/";
hosts = await (await fetch(fetch_url.concat(domain))).json();
} catch(err) {
console.log('\n\nCant get hosts err: ' + err);
exit(1);
}
//Parse users hosts
for(const host of hosts.data) {
if(!isEmail && host.domain != null && host.domain.toLowerCase().includes(domain.toLowerCase()))
{
balance = await getXahauBalance(host.address);
hosts_accounts.push([host.domain,host.address,balance])
} else if(host.email != null && host.email.toLowerCase().includes(domain.toLowerCase()))
{
balance = await getXahauBalance(host.address);
hosts_accounts.push([host.domain,host.address,balance])
}
}
if(hosts_accounts.length == 0)
{
console.log('Cant find Hosts under this ' + (isEmail? 'Email' : 'Domain'));
exit(1);
}
//Display information
console.log('\n\nDetected ' + hosts_accounts.length + ' Hosts under this domain:');
for(const host_account of hosts_accounts)
{
console.log('Domain: ' + host_account[0] + ' Account: ' + host_account[1] + ' XAH balance: ' + host_account[2] + ' XAH');
}
//Query users request for top up
var amount = "_"
rl.question('\n\nSpecify to what value of XAH to Top up each host:', (answer) => {
amount = answer;
});
while (amount == "_") { await new Promise(r => setTimeout(r, 100)) }
var seed = "_"
rl.question('\nSpecify The secret key(seed) of the sender:', (answer) => {
seed = answer;
});
while (seed == "_") { await new Promise(r => setTimeout(r, 100)) }
var needed_xahah = 0;
//Calculate amount needed for Transfer
for(const host_account of hosts_accounts)
{
if(amount - host_account[2] > 0)
needed_xahah += amount - host_account[2];
}
//If top up is lower than needed just exit now
if(needed_xahah == 0)
{
console.log('\nAll Your accounts already have the desired XAH balance, not doing anything BA BYE');
exit(1);
}
//Issue notice to user about needed amount from sender
wallet = xrpl.Wallet.fromSeed(seed);
console.log('\n\n !!!! Please Verify the sender['+ wallet.address + '] has: ' + needed_xahah.toFixed(3) + ' XAH available to send!!!!!');
//Fire up last consent to start sending it out
var consent = "_"
rl.question('\nDo you wish to start sending now?[y/N]', (answer) => {
consent = answer;
});
while (consent == "_") { await new Promise(r => setTimeout(r, 100)) }
if(consent.toLowerCase() != 'y')
{
console.log('K BA BYE');
exit(1);
}
//Sending
console.log('\n\n Sending using account[' + wallet.address + '] Please wait...');
for(const host_account of hosts_accounts)
{
var send_amount = amount - host_account[2];
//Skip hosts with higher top up amount
if(send_amount.toFixed(3) <= 0)
{
console.log('\nSkipping ' + host_account[0] + '[' + host_account[1] + '] it already has : ' + host_account[2] + ' XAH');
continue;
}
//Allow for 3 retries if it failes
var retry = 3;
var result = "";
while(result != 'tesSUCCESS' && retry > 0)
{
try{
result = await sendXahau(wallet, host_account[0], host_account[1], send_amount.toFixed(3), retry);
} catch(error) {
console.log('\nFailed payment attempt error: ' + error);
}
retry--;
}
if(result != 'tesSUCCESS')
console.log('\nFailed sending to: ' + host_account[0] + '[' + host_account[1] + '] after 3 retries result:' + result);
else
console.log('\nSent ' + send_amount.toFixed(3) + ' XAH to:' + host_account[0] + '[' + host_account[1] + ']');
}
//Print out accounts balances after the transfers
console.log('\n\nFinished sending Hosts stautus after:');
for(const host_account of hosts_accounts)
{
var balance_after = await getXahauBalance(host_account[1]);
console.log('Domain: ' + host_account[0] + ' Account: ' + host_account[1] + ' XAH balance: ' + balance_after + ' XAH');
}
console.log('\nAll done BA BYE');
exit(1);
}
main()