evernode-js-client 0.4.51 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.json +14 -0
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/clean-pkg.sh +4 -0
- package/npm-readme.md +4 -0
- package/package.json +16 -1
- package/remove-versions.sh +10 -0
- package/src/clients/base-evernode-client.js +567 -0
- package/src/clients/host-client.js +357 -0
- package/src/clients/registry-client.js +52 -0
- package/src/clients/tenant-client.js +264 -0
- package/src/defaults.js +21 -0
- package/src/eccrypto.js +258 -0
- package/src/encryption-helper.js +41 -0
- package/src/event-emitter.js +45 -0
- package/src/evernode-common.js +103 -0
- package/src/evernode-helpers.js +14 -0
- package/src/firestore/firestore-handler.js +309 -0
- package/src/index.js +37 -0
- package/src/state-helpers.js +283 -0
- package/src/transaction-helper.js +62 -0
- package/src/util-helpers.js +48 -0
- package/src/xfl-helpers.js +130 -0
- package/src/xrpl-account.js +473 -0
- package/src/xrpl-api.js +275 -0
- package/src/xrpl-common.js +17 -0
- package/test/package-lock.json +884 -0
- package/test/package.json +9 -0
- package/test/test.js +379 -0
- package/index.js +0 -15129
package/test/test.js
ADDED
@@ -0,0 +1,379 @@
|
|
1
|
+
// const evernode = require("evernode-js-client");
|
2
|
+
const evernode = require("../dist"); // Local dist dir. (use 'npm run build' to update)
|
3
|
+
const codec = require('ripple-address-codec');
|
4
|
+
|
5
|
+
// const evrIssuerAddress = "rEm71QHHXJzGULG4mkR3yhLz6EZYgvuwwP";
|
6
|
+
// const registryAddress = "raaFre81618XegCrzTzVotAmarBcqNSAvK";
|
7
|
+
// const registrySecret = "snrUSoLVodmhVCDNL92K1UafzQDjH";
|
8
|
+
// const hostAddress = "rNJDQu9pUretQetmxeHRPkasM4o7chdML2";
|
9
|
+
// const hostSecret = "ss11mwRSG4UxXQ9LakyYTmAzisnN2";
|
10
|
+
// const foundationAddress = "rMRRzwe2mPhtVJYkBsPYbxkrHdExAduqWi";
|
11
|
+
// const foundationSecret = "sncQEvGmeMrVGAvkMiLkmE3hrtVH9";
|
12
|
+
// const tenantAddress = "rw7GPreCDX2nuJVHSwNdH38ZGsiEH8qiY";
|
13
|
+
// const tenantSecret = "shdQBGbF9d3Tgp3D28pXoBdhWoZ9N";
|
14
|
+
// const initializerAddress = 'rMv668j9M6x2ww4HNEF4AhB8ju77oSxFJD';
|
15
|
+
// const initializerSecret = 'sn6TNZivVQY9KxXrLy8XdH9oXk3aG';
|
16
|
+
|
17
|
+
const evrIssuerAddress = "rfxLPXCcSmwR99dV97yFozBzrzpvCa2VCf";
|
18
|
+
const registryAddress = "r3cNR2bdao1NyvQ5ZuQvCUgqkoWGmgF34E";
|
19
|
+
const registrySecret = "saNjrsgXSB14J27mimdgqNnJpTaP9";
|
20
|
+
const hostAddress = "rNJDQu9pUretQetmxeHRPkasM4o7chdML2";
|
21
|
+
const hostSecret = "ss11mwRSG4UxXQ9LakyYTmAzisnN2";
|
22
|
+
const foundationAddress = "rppVLpTDks7tjAGw9TRcwqMGzuDvzV72Vh";
|
23
|
+
const foundationSecret = "shdAf9oUv1TLVTTR26Ke7w7Gv44HN";
|
24
|
+
const tenantAddress = "rw7GPreCDX2nuJVHSwNdH38ZGsiEH8qiY";
|
25
|
+
const tenantSecret = "shdQBGbF9d3Tgp3D28pXoBdhWoZ9N";
|
26
|
+
const initializerAddress = 'rMv668j9M6x2ww4HNEF4AhB8ju77oSxFJD';
|
27
|
+
const initializerSecret = 'sn6TNZivVQY9KxXrLy8XdH9oXk3aG';
|
28
|
+
|
29
|
+
const tosHash = "757A0237B44D8B2BBB04AE2BAD5813858E0AECD2F0B217075E27E0630BA74314";
|
30
|
+
|
31
|
+
const clients = [];
|
32
|
+
|
33
|
+
async function app() {
|
34
|
+
|
35
|
+
// Use a singleton xrplApi for all tests.
|
36
|
+
const xrplApi = new evernode.XrplApi('wss://hooks-testnet-v2.xrpl-labs.com');
|
37
|
+
evernode.Defaults.set({
|
38
|
+
registryAddress: registryAddress,
|
39
|
+
xrplApi: xrplApi
|
40
|
+
})
|
41
|
+
|
42
|
+
try {
|
43
|
+
await xrplApi.connect();
|
44
|
+
|
45
|
+
const registryClient = new evernode.RegistryClient({registryAddress: 'r3cNR2bdao1NyvQ5ZuQvCUgqkoWGmgF34E'});
|
46
|
+
const status = await registryClient.connect();
|
47
|
+
const res = await registryClient.getAllConfigs();
|
48
|
+
console.log(res);
|
49
|
+
|
50
|
+
|
51
|
+
// Process of minting and selling a NFT.
|
52
|
+
|
53
|
+
// Account1: selling party.
|
54
|
+
// const acc1 = new evernode.XrplAccount(ownerAddress, ownerSecret);
|
55
|
+
// // Mint an nft with some data included in uri (256 bytes). xrpl doesn't check for uniqueness of data.
|
56
|
+
// // We need to make it unique in order to later find the token by uri.
|
57
|
+
// const uri = "mynft custom data";
|
58
|
+
// await acc1.mintNft(uri, 0, 0, true);
|
59
|
+
// // Get the minted nft information and sell it on the dex.
|
60
|
+
// const nft = await acc1.getNftByUri(uri);
|
61
|
+
// console.log(nft);
|
62
|
+
// // Make a sell offer (for free) while restricting it to be only purchased by the specified party.
|
63
|
+
// await acc1.offerSellNft(nft.NFTokenID, '0', 'XRP', null, hostAddress);
|
64
|
+
|
65
|
+
// // Account2: Buying party.
|
66
|
+
// const acc2 = new evernode.XrplAccount(hostAddress, hostSecret);
|
67
|
+
// // await acc2.offerBuyNft(nft.NFTokenID, registryAddress, '10', 'EVR', evrIssuerAddress);
|
68
|
+
|
69
|
+
// // const offers = await acc1.getNftOffers();
|
70
|
+
// // console.log(offers);
|
71
|
+
// // Find the sellOffer information from seller's account.
|
72
|
+
// const sellOffer = (await acc1.getNftOffers()).find(o => o.NFTokenID == nft.NFTokenID);
|
73
|
+
// console.log(sellOffer);
|
74
|
+
// // Buy the NFT by accepting the sell offer.
|
75
|
+
// await acc2.buyNft(sellOffer.index);
|
76
|
+
// // Get information about the purchased nft.
|
77
|
+
// const nft2 = await acc2.getNftByUri(uri);
|
78
|
+
// console.log(nft2);
|
79
|
+
|
80
|
+
const tests = [
|
81
|
+
// () => initializeConfigs(),
|
82
|
+
// () => getHookStates(),
|
83
|
+
// () => registerHost(),
|
84
|
+
// () => getHostInfo(),
|
85
|
+
// () => updateInfo(),
|
86
|
+
// () => getAllHosts(),
|
87
|
+
// () => getActiveHosts(),
|
88
|
+
// () => heartbeatHost(),
|
89
|
+
// () => acquire("success"),
|
90
|
+
// () => acquire("error"),
|
91
|
+
// () => acquire("timeout"),
|
92
|
+
// () => extendLease("success"),
|
93
|
+
// () => extendLease("error"),
|
94
|
+
// () => extendLease("timeout"),
|
95
|
+
// () => deregisterHost(),
|
96
|
+
// () => getAllConfigs(),
|
97
|
+
// () => pruneDeadHost(),
|
98
|
+
|
99
|
+
];
|
100
|
+
|
101
|
+
for (const test of tests) {
|
102
|
+
await test();
|
103
|
+
await Promise.all(clients.map(c => c.disconnect())); // Cleanup clients after every test.
|
104
|
+
}
|
105
|
+
|
106
|
+
// await registerHost();
|
107
|
+
// Accepting the sell offer created by registry.
|
108
|
+
|
109
|
+
// const tokenID = '0008000083CD166E1806EF2076C55077AEFD418E771A516CB30E8CAE00000013';
|
110
|
+
// const reg = new evernode.XrplAccount(registryAddress, registrySecret);
|
111
|
+
// const sellOffer = (await reg.getNftOffers()).find(o => o.NFTokenID == tokenID);
|
112
|
+
// console.log(sellOffer);
|
113
|
+
// const host = new evernode.XrplAccount(hostAddress, hostSecret);
|
114
|
+
// await host.buyNft(sellOffer.index);
|
115
|
+
// const nfts = await host.getNfts();
|
116
|
+
// console.log(nfts);
|
117
|
+
// await host.register();
|
118
|
+
// await initializeConfigs();
|
119
|
+
// await registerHost();
|
120
|
+
// await deregisterHost();
|
121
|
+
// await getHookStates()
|
122
|
+
|
123
|
+
}
|
124
|
+
catch (e) {
|
125
|
+
console.error("Error occured:", e);
|
126
|
+
}
|
127
|
+
finally {
|
128
|
+
// Added this timeout since some tests failed with not connected error.
|
129
|
+
await new Promise(resolve => setTimeout(resolve, 4000)); // Wait for four seconds before disconnecting.
|
130
|
+
await xrplApi.disconnect();
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
async function updateInfo() {
|
135
|
+
console.log(`-----------Update host`);
|
136
|
+
|
137
|
+
const client = await getHostClient();
|
138
|
+
await client.updateRegInfo(10);
|
139
|
+
}
|
140
|
+
|
141
|
+
async function getActiveHosts() {
|
142
|
+
console.log(`-----------Getting active hosts`);
|
143
|
+
|
144
|
+
const regClient = await getRegistryClient();
|
145
|
+
const hosts = await regClient.getActiveHosts();
|
146
|
+
|
147
|
+
console.log("Hosts", hosts || "No active hosts");
|
148
|
+
}
|
149
|
+
|
150
|
+
async function initializeConfigs() {
|
151
|
+
console.log(`-----------Initialize configs`);
|
152
|
+
let memoData = Buffer.allocUnsafe(40);
|
153
|
+
codec.decodeAccountID(evrIssuerAddress).copy(memoData);
|
154
|
+
codec.decodeAccountID(foundationAddress).copy(memoData, 20);
|
155
|
+
|
156
|
+
const initAccount = new evernode.XrplAccount(initializerAddress, initializerSecret);
|
157
|
+
await initAccount.makePayment(registryAddress, '1', 'XRP', null,
|
158
|
+
[{ type: 'evnInitialize', format: 'hex', data: memoData.toString('hex') }]);
|
159
|
+
}
|
160
|
+
|
161
|
+
async function registerHost(address = hostAddress, secret = hostSecret) {
|
162
|
+
const host = await getHostClient(address, secret);
|
163
|
+
|
164
|
+
if (await host.isRegistered())
|
165
|
+
return true;
|
166
|
+
|
167
|
+
console.log(`-----------Register host`);
|
168
|
+
|
169
|
+
// Prepare host account for Evernode.
|
170
|
+
console.log("Prepare...");
|
171
|
+
await host.prepareAccount("mydomain.com");
|
172
|
+
|
173
|
+
// Get EVRs from the foundation if needed.
|
174
|
+
const lines = await host.xrplAcc.getTrustLines(evernode.EvernodeConstants.EVR, evrIssuerAddress);
|
175
|
+
if (lines.length === 0 || parseInt(lines[0].balance) < 5120) {
|
176
|
+
console.log("Transfer EVRs...");
|
177
|
+
const foundationAcc = new evernode.XrplAccount(foundationAddress, foundationSecret);
|
178
|
+
await foundationAcc.makePayment(address, "5120", evernode.EvernodeConstants.EVR, evrIssuerAddress);
|
179
|
+
}
|
180
|
+
|
181
|
+
console.log("Register...");
|
182
|
+
const instanceCount = 3;
|
183
|
+
await host.register("AU", 10000, 512, 1024, instanceCount, 'Intel', 10, 10, "Test desctiption", 2);
|
184
|
+
|
185
|
+
console.log("Lease Offer...");
|
186
|
+
for (let i = 0; i < instanceCount; i++)
|
187
|
+
await host.offerLease(i, 2, tosHash);
|
188
|
+
|
189
|
+
// Verify the registration.
|
190
|
+
return await host.isRegistered();
|
191
|
+
}
|
192
|
+
|
193
|
+
async function deregisterHost(address = hostAddress, secret = hostSecret) {
|
194
|
+
const host = await getHostClient(address, secret);
|
195
|
+
|
196
|
+
if (!await host.isRegistered())
|
197
|
+
return true;
|
198
|
+
|
199
|
+
console.log(`-----------Deregister host`);
|
200
|
+
|
201
|
+
await host.deregister();
|
202
|
+
|
203
|
+
// Burn NFTs.
|
204
|
+
const nfts = (await host.xrplAcc.getNfts()).filter(n => n.URI.startsWith(evernode.EvernodeConstants.LEASE_NFT_PREFIX_HEX))
|
205
|
+
.map(o => { return { nfTokenId: o.NFTokenID, ownerAddress: host.xrplAcc.address }; });
|
206
|
+
for (const nft of nfts) {
|
207
|
+
const sold = nft.ownerAddress !== host.xrplAcc.address;
|
208
|
+
await host.xrplAcc.burnNft(nft.nfTokenId, sold ? nft.ownerAddress : null);
|
209
|
+
console.log(`Burnt ${sold ? 'sold' : 'unsold'} hosting NFT (${nft.nfTokenId}) of ${nft.ownerAddress + (sold ? ' tenant' : '')} account`);
|
210
|
+
}
|
211
|
+
|
212
|
+
// Verify the deregistration.
|
213
|
+
return !await host.isRegistered();
|
214
|
+
}
|
215
|
+
|
216
|
+
async function heartbeatHost(address = hostAddress, secret = hostSecret) {
|
217
|
+
const host = await getHostClient(address, secret);
|
218
|
+
|
219
|
+
if (!await host.isRegistered())
|
220
|
+
return true;
|
221
|
+
|
222
|
+
console.log(`-----------Heartbeat host`);
|
223
|
+
|
224
|
+
await host.heartbeat();
|
225
|
+
}
|
226
|
+
|
227
|
+
async function acquire(scenario) {
|
228
|
+
console.log(`-----------Acquire (${scenario})`);
|
229
|
+
|
230
|
+
const tenant = await getTenantClient();
|
231
|
+
await tenant.prepareAccount();
|
232
|
+
|
233
|
+
// Setup host to watch for incoming acquires.
|
234
|
+
const host = await getHostClient();
|
235
|
+
|
236
|
+
host.on(evernode.HostEvents.AcquireLease, async (r) => {
|
237
|
+
console.log("Host received acquire request: ", r.payload);
|
238
|
+
|
239
|
+
if (scenario !== "timeout") {
|
240
|
+
console.log(`Host submitting ${scenario} response...`);
|
241
|
+
await new Promise(resolve => setTimeout(resolve, 4000));
|
242
|
+
|
243
|
+
if (scenario === "success")
|
244
|
+
await host.acquireSuccess(r.acquireRefId, r.tenant, { content: "dummy success" });
|
245
|
+
else if (scenario === "error") {
|
246
|
+
const nft = (await (new evernode.XrplAccount(r.tenant)).getNfts())?.find(n => n.NFTokenID == r.nfTokenId);
|
247
|
+
const leaseIndex = Buffer.from(nft.URI, 'hex').readUint16BE(evernode.EvernodeConstants.LEASE_NFT_PREFIX_HEX.length);
|
248
|
+
|
249
|
+
await host.expireLease(r.nfTokenId, r.tenant);
|
250
|
+
await host.offerLease(leaseIndex, r.leaseAmount, tosHash);
|
251
|
+
await host.acquireError(r.acquireRefId, r.tenant, r.leaseAmount, "dummy_error");
|
252
|
+
}
|
253
|
+
}
|
254
|
+
})
|
255
|
+
|
256
|
+
await fundTenant(tenant);
|
257
|
+
|
258
|
+
try {
|
259
|
+
const timeout = (scenario === "timeout" ? 10000 : 30000);
|
260
|
+
const result = await tenant.acquireLease(hostAddress, {
|
261
|
+
owner_pubkey: "ed5cb83404120ac759609819591ef839b7d222c84f1f08b3012f490586159d2b50",
|
262
|
+
contract_id: "dc411912-bcdd-4f73-af43-32ec45844b9a",
|
263
|
+
image: "hp.latest-ubt.20.04-njs.16",
|
264
|
+
config: {}
|
265
|
+
}, { timeout: timeout });
|
266
|
+
console.log('Tenant received instance ', result.instance);
|
267
|
+
}
|
268
|
+
catch (err) {
|
269
|
+
console.log("Tenant recieved acquire error: ", err.reason)
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
async function extendLease(scenario) {
|
274
|
+
console.log(`-----------Extend lease (${scenario})`);
|
275
|
+
|
276
|
+
const tenant = await getTenantClient();
|
277
|
+
await tenant.prepareAccount();
|
278
|
+
|
279
|
+
// Setup host to watch for incoming acquires.
|
280
|
+
const host = await getHostClient();
|
281
|
+
|
282
|
+
host.on(evernode.HostEvents.ExtendLease, async (r) => {
|
283
|
+
|
284
|
+
console.log(`Host received extend request for: '${r.nfTokenId}'`);
|
285
|
+
|
286
|
+
console.log(`Host submitting ${scenario} response...`);
|
287
|
+
await new Promise(resolve => setTimeout(resolve, 4000));
|
288
|
+
|
289
|
+
if (scenario === "success")
|
290
|
+
await host.extendSuccess(r.extendRefId, r.tenant, { content: "dummy success" }).catch(console.error);
|
291
|
+
else if (scenario === "error") {
|
292
|
+
await host.extendError(r.extendRefId, r.tenant, "dummy_error", r.payment.toString()).catch(console.error);
|
293
|
+
}
|
294
|
+
})
|
295
|
+
|
296
|
+
await fundTenant(tenant);
|
297
|
+
|
298
|
+
try {
|
299
|
+
const timeout = (scenario === "timeout" ? 10000 : 30000);
|
300
|
+
const tokenIDs = (await tenant.xrplAcc.getNfts()).map(n => n.NFTokenID);
|
301
|
+
const result = await tenant.extendLease(hostAddress, 2, tokenIDs[0], { timeout: timeout });
|
302
|
+
console.log(`Extend ref id: ${result.extendeRefId}, Expiry moments: ${result.expiryMoment}`);
|
303
|
+
}
|
304
|
+
catch (err) {
|
305
|
+
console.log("Tenant recieved extend error: ", err.reason)
|
306
|
+
}
|
307
|
+
}
|
308
|
+
//////////////////////////////////////////////////////////////////////////////////////
|
309
|
+
|
310
|
+
async function getTenantClient() {
|
311
|
+
const client = new evernode.TenantClient(tenantAddress, tenantSecret);
|
312
|
+
await client.connect();
|
313
|
+
clients.push(client);
|
314
|
+
return client;
|
315
|
+
}
|
316
|
+
|
317
|
+
async function getHostClient(address = hostAddress, secret = hostSecret) {
|
318
|
+
const client = new evernode.HostClient(address, secret);
|
319
|
+
await client.connect();
|
320
|
+
clients.push(client);
|
321
|
+
return client;
|
322
|
+
}
|
323
|
+
|
324
|
+
async function getRegistryClient() {
|
325
|
+
const client = new evernode.RegistryClient(registryAddress, registrySecret);
|
326
|
+
await client.connect();
|
327
|
+
clients.push(client);
|
328
|
+
return client;
|
329
|
+
}
|
330
|
+
|
331
|
+
async function fundTenant(tenant) {
|
332
|
+
// Send hosting tokens to tenant if needed.
|
333
|
+
const lines = await tenant.xrplAcc.getTrustLines('EVR', evrIssuerAddress);
|
334
|
+
if (lines.length === 0 || parseInt(lines[0].balance) < 1) {
|
335
|
+
await tenant.xrplAcc.setTrustLine('EVR', evrIssuerAddress, "99999999");
|
336
|
+
await new evernode.XrplAccount(foundationAddress, foundationSecret).makePayment(tenantAddress, "1000", 'EVR', evrIssuerAddress);
|
337
|
+
}
|
338
|
+
}
|
339
|
+
|
340
|
+
async function getHookStates() {
|
341
|
+
const registryClient = new evernode.RegistryClient(registryAddress, registrySecret);
|
342
|
+
await registryClient.connect();
|
343
|
+
const states = await registryClient.getHookStates();
|
344
|
+
console.log(states.length, states);
|
345
|
+
}
|
346
|
+
|
347
|
+
async function getAllHosts() {
|
348
|
+
console.log(`-----------Getting all hosts (including inactive)`);
|
349
|
+
const registryClient = new evernode.RegistryClient(registryAddress, registrySecret);
|
350
|
+
await registryClient.connect();
|
351
|
+
const hosts = await registryClient.getAllHosts();
|
352
|
+
console.log(hosts.length, hosts);
|
353
|
+
}
|
354
|
+
|
355
|
+
|
356
|
+
async function getAllConfigs() {
|
357
|
+
console.log(`-----------Getting all configs`);
|
358
|
+
const registryClient = new evernode.RegistryClient(registryAddress, registrySecret);
|
359
|
+
await registryClient.connect();
|
360
|
+
const configs = await registryClient.getAllConfigs();
|
361
|
+
console.log(configs.length, configs);
|
362
|
+
}
|
363
|
+
|
364
|
+
async function getHostInfo() {
|
365
|
+
const host = await getHostClient();
|
366
|
+
const hostInfo = await host.getHostInfo();
|
367
|
+
console.log(hostInfo);
|
368
|
+
return hostInfo;
|
369
|
+
}
|
370
|
+
|
371
|
+
async function pruneDeadHost(address = hostAddress) {
|
372
|
+
console.log(`-----------Prune host`);
|
373
|
+
|
374
|
+
// Create a cleint to send the prune request (the client can be a tenant or another host).
|
375
|
+
const tenantClient = await getTenantClient();
|
376
|
+
await tenantClient.pruneDeadHost(address);
|
377
|
+
}
|
378
|
+
|
379
|
+
app();
|