evernode-js-client 0.5.9 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- package/index.js +262 -47
- package/package.json +1 -1
package/index.js
CHANGED
@@ -11732,6 +11732,7 @@ const { EventEmitter } = __nccwpck_require__(6170);
|
|
11732
11732
|
const { UtilHelpers } = __nccwpck_require__(6687);
|
11733
11733
|
const { FirestoreHandler } = __nccwpck_require__(9718);
|
11734
11734
|
const { StateHelpers } = __nccwpck_require__(3860);
|
11735
|
+
const { EvernodeHelpers } = __nccwpck_require__(2523);
|
11735
11736
|
|
11736
11737
|
class BaseEvernodeClient {
|
11737
11738
|
|
@@ -12037,17 +12038,13 @@ class BaseEvernodeClient {
|
|
12037
12038
|
}
|
12038
12039
|
}
|
12039
12040
|
else if (tx.Memos.length >= 1 &&
|
12040
|
-
tx.Memos[0].type === MemoTypes.HOST_REG && tx.Memos[0].format === MemoFormats.
|
12041
|
+
tx.Memos[0].type === MemoTypes.HOST_REG && tx.Memos[0].format === MemoFormats.HEX && tx.Memos[0].data) {
|
12041
12042
|
|
12042
|
-
const parts = tx.Memos[0].data.split(';');
|
12043
12043
|
return {
|
12044
12044
|
name: EvernodeEvents.HostRegistered,
|
12045
12045
|
data: {
|
12046
12046
|
transaction: tx,
|
12047
|
-
host: tx.Account
|
12048
|
-
token: parts[0],
|
12049
|
-
instanceSize: parts[1],
|
12050
|
-
location: parts[2]
|
12047
|
+
host: tx.Account
|
12051
12048
|
}
|
12052
12049
|
}
|
12053
12050
|
}
|
@@ -12135,17 +12132,13 @@ class BaseEvernodeClient {
|
|
12135
12132
|
}
|
12136
12133
|
}
|
12137
12134
|
else if (tx.Memos.length >= 1 &&
|
12138
|
-
tx.Memos[0].type === MemoTypes.HOST_UPDATE_INFO && tx.Memos[0].format === MemoFormats.
|
12139
|
-
|
12140
|
-
const specs = tx.Memos[0].data.split(';');
|
12135
|
+
tx.Memos[0].type === MemoTypes.HOST_UPDATE_INFO && tx.Memos[0].format === MemoFormats.HEX && tx.Memos[0].data) {
|
12141
12136
|
|
12142
12137
|
return {
|
12143
12138
|
name: EvernodeEvents.HostRegUpdated,
|
12144
12139
|
data: {
|
12145
12140
|
transaction: tx,
|
12146
|
-
host: tx.Account
|
12147
|
-
version: specs[specs.length - 1],
|
12148
|
-
specs: specs,
|
12141
|
+
host: tx.Account
|
12149
12142
|
}
|
12150
12143
|
}
|
12151
12144
|
}
|
@@ -12238,13 +12231,16 @@ class BaseEvernodeClient {
|
|
12238
12231
|
async getHosts(filters = null, pageSize = null, nextPageToken = null) {
|
12239
12232
|
const hosts = await this.#firestoreHandler.getHosts(filters, pageSize, nextPageToken);
|
12240
12233
|
const curMomentStartIdx = await this.getMomentStartIndex();
|
12241
|
-
|
12242
|
-
(hosts.nextPageToken ? hosts.data : hosts).
|
12243
|
-
|
12244
|
-
|
12245
|
-
|
12246
|
-
|
12247
|
-
|
12234
|
+
|
12235
|
+
return await Promise.all((hosts.nextPageToken ? hosts.data : hosts).map(async host => {
|
12236
|
+
const hostAcc = new XrplAccount(host.address);
|
12237
|
+
host.domain = await hostAcc.getDomain();
|
12238
|
+
|
12239
|
+
host.active = (host.lastHeartbeatIndex > (this.config.hostHeartbeatFreq * this.config.momentSize) ?
|
12240
|
+
(host.lastHeartbeatIndex >= (curMomentStartIdx - (this.config.hostHeartbeatFreq * this.config.momentSize))) :
|
12241
|
+
(host.lastHeartbeatIndex > 0));
|
12242
|
+
return host;
|
12243
|
+
}));
|
12248
12244
|
}
|
12249
12245
|
|
12250
12246
|
/**
|
@@ -12304,11 +12300,28 @@ class BaseEvernodeClient {
|
|
12304
12300
|
let memoData = Buffer.allocUnsafe(20);
|
12305
12301
|
codec.decodeAccountID(hostAddress).copy(memoData);
|
12306
12302
|
|
12307
|
-
|
12308
|
-
|
12309
|
-
|
12310
|
-
|
12311
|
-
|
12303
|
+
// To obtain registration NFT Page Keylet and index.
|
12304
|
+
const hostAcc = new XrplAccount(hostAddress, null, { xrplApi: this.xrplApi });
|
12305
|
+
const regNFT = (await hostAcc.getNfts()).find(n => n.URI.startsWith(EvernodeConstants.NFT_PREFIX_HEX) && n.Issuer === this.registryAddress);
|
12306
|
+
if (regNFT) {
|
12307
|
+
// Check whether the token was actually issued from Evernode registry contract.
|
12308
|
+
const issuerHex = regNFT.NFTokenID.substr(8, 40);
|
12309
|
+
const issuerAddr = codec.encodeAccountID(Buffer.from(issuerHex, 'hex'));
|
12310
|
+
if (issuerAddr == this.registryAddress) {
|
12311
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(regNFT.NFTokenID, hostAcc, this.xrplApi);
|
12312
|
+
|
12313
|
+
await this.xrplAcc.makePayment(this.registryAddress,
|
12314
|
+
XrplConstants.MIN_XRP_AMOUNT,
|
12315
|
+
XrplConstants.XRP,
|
12316
|
+
null,
|
12317
|
+
[
|
12318
|
+
{ type: MemoTypes.DEAD_HOST_PRUNE, format: MemoFormats.HEX, data: memoData.toString('hex') },
|
12319
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12320
|
+
]);
|
12321
|
+
} else
|
12322
|
+
throw "Invalid Registration NFT."
|
12323
|
+
} else
|
12324
|
+
throw "No Registration NFT was found for the Host account."
|
12312
12325
|
|
12313
12326
|
}
|
12314
12327
|
}
|
@@ -12341,6 +12354,29 @@ const HostEvents = {
|
|
12341
12354
|
ExtendLease: EvernodeEvents.ExtendLease
|
12342
12355
|
}
|
12343
12356
|
|
12357
|
+
const HOST_COUNTRY_CODE_MEMO_OFFSET = 0;
|
12358
|
+
const HOST_CPU_MICROSEC_MEMO_OFFSET = 2;
|
12359
|
+
const HOST_RAM_MB_MEMO_OFFSET = 6;
|
12360
|
+
const HOST_DISK_MB_MEMO_OFFSET = 10;
|
12361
|
+
const HOST_TOT_INS_COUNT_MEMO_OFFSET = 14;
|
12362
|
+
const HOST_CPU_MODEL_NAME_MEMO_OFFSET = 18;
|
12363
|
+
const HOST_CPU_COUNT_MEMO_OFFSET = 58;
|
12364
|
+
const HOST_CPU_SPEED_MEMO_OFFSET = 60;
|
12365
|
+
const HOST_DESCRIPTION_MEMO_OFFSET = 62;
|
12366
|
+
const HOST_EMAIL_ADDRESS_MEMO_OFFSET = 88;
|
12367
|
+
const HOST_REG_MEMO_SIZE = 128;
|
12368
|
+
|
12369
|
+
const HOST_UPDATE_TOKEN_ID_MEMO_OFFSET = 0;
|
12370
|
+
const HOST_UPDATE_COUNTRY_CODE_MEMO_OFFSET = 32;
|
12371
|
+
const HOST_UPDATE_CPU_MICROSEC_MEMO_OFFSET = 34;
|
12372
|
+
const HOST_UPDATE_RAM_MB_MEMO_OFFSET = 38;
|
12373
|
+
const HOST_UPDATE_DISK_MB_MEMO_OFFSET = 42;
|
12374
|
+
const HOST_UPDATE_TOT_INS_COUNT_MEMO_OFFSET = 46;
|
12375
|
+
const HOST_UPDATE_ACT_INS_COUNT_MEMO_OFFSET = 50;
|
12376
|
+
const HOST_UPDATE_DESCRIPTION_MEMO_OFFSET = 54;
|
12377
|
+
const HOST_UPDATE_VERSION_MEMO_OFFSET = 80;
|
12378
|
+
const HOST_UPDATE_MEMO_SIZE = 83;
|
12379
|
+
|
12344
12380
|
class HostClient extends BaseEvernodeClient {
|
12345
12381
|
|
12346
12382
|
constructor(xrpAddress, xrpSecret, options = {}) {
|
@@ -12460,8 +12496,8 @@ class HostClient extends BaseEvernodeClient {
|
|
12460
12496
|
throw "description should consist of 0-26 ascii characters except ';'";
|
12461
12497
|
|
12462
12498
|
else if (!emailAddress || !(/[a-z0-9]+@[a-z]+.[a-z]{2,3}/.test(emailAddress)) || (emailAddress.length > 40))
|
12463
|
-
throw "Email address should be valid and can not have more than 40 characters.";
|
12464
|
-
|
12499
|
+
throw "Email address should be valid and can not have more than 40 characters.";
|
12500
|
+
|
12465
12501
|
if (await this.isRegistered())
|
12466
12502
|
throw "Host already registered.";
|
12467
12503
|
|
@@ -12501,12 +12537,24 @@ class HostClient extends BaseEvernodeClient {
|
|
12501
12537
|
console.log("No initiated transfers were found.");
|
12502
12538
|
}
|
12503
12539
|
|
12504
|
-
|
12540
|
+
// <country_code(2)><cpu_microsec(4)><ram_mb(4)><disk_mb(4)><no_of_total_instances(4)><cpu_model(40)><cpu_count(2)><cpu_speed(2)><description(26)><email_address(40)>
|
12541
|
+
const memoBuf = Buffer.alloc(HOST_REG_MEMO_SIZE, 0);
|
12542
|
+
Buffer.from(countryCode.substr(0, 2), "utf-8").copy(memoBuf, HOST_COUNTRY_CODE_MEMO_OFFSET);
|
12543
|
+
memoBuf.writeUInt32BE(cpuMicroSec, HOST_CPU_MICROSEC_MEMO_OFFSET);
|
12544
|
+
memoBuf.writeUInt32BE(ramMb, HOST_RAM_MB_MEMO_OFFSET);
|
12545
|
+
memoBuf.writeUInt32BE(diskMb, HOST_DISK_MB_MEMO_OFFSET);
|
12546
|
+
memoBuf.writeUInt32BE(totalInstanceCount, HOST_TOT_INS_COUNT_MEMO_OFFSET);
|
12547
|
+
Buffer.from(cpuModel.substr(0, 40), "utf-8").copy(memoBuf, HOST_CPU_MODEL_NAME_MEMO_OFFSET);
|
12548
|
+
memoBuf.writeUInt16BE(cpuCount, HOST_CPU_COUNT_MEMO_OFFSET);
|
12549
|
+
memoBuf.writeUInt16BE(cpuSpeed, HOST_CPU_SPEED_MEMO_OFFSET);
|
12550
|
+
Buffer.from(description.substr(0, 26), "utf-8").copy(memoBuf, HOST_DESCRIPTION_MEMO_OFFSET);
|
12551
|
+
Buffer.from(emailAddress.substr(0, 40), "utf-8").copy(memoBuf, HOST_EMAIL_ADDRESS_MEMO_OFFSET);
|
12552
|
+
|
12505
12553
|
const tx = await this.xrplAcc.makePayment(this.registryAddress,
|
12506
12554
|
(transferredNFTokenId) ? EvernodeConstants.NOW_IN_EVRS : this.config.hostRegFee.toString(),
|
12507
12555
|
EvernodeConstants.EVR,
|
12508
12556
|
this.config.evrIssuerAddress,
|
12509
|
-
[{ type: MemoTypes.HOST_REG, format: MemoFormats.
|
12557
|
+
[{ type: MemoTypes.HOST_REG, format: MemoFormats.HEX, data: memoBuf.toString('hex') }],
|
12510
12558
|
options.transactionOptions);
|
12511
12559
|
|
12512
12560
|
console.log('Waiting for the sell offer')
|
@@ -12551,11 +12599,18 @@ class HostClient extends BaseEvernodeClient {
|
|
12551
12599
|
throw "Host not registered."
|
12552
12600
|
|
12553
12601
|
const regNFT = await this.getRegistrationNft();
|
12602
|
+
|
12603
|
+
// To obtain registration NFT Page Keylet and index.
|
12604
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(regNFT.NFTokenID, this.xrplAcc, this.xrplApi);
|
12605
|
+
|
12554
12606
|
await this.xrplAcc.makePayment(this.registryAddress,
|
12555
12607
|
XrplConstants.MIN_XRP_AMOUNT,
|
12556
12608
|
XrplConstants.XRP,
|
12557
12609
|
null,
|
12558
|
-
[
|
12610
|
+
[
|
12611
|
+
{ type: MemoTypes.HOST_DEREG, format: MemoFormats.HEX, data: regNFT.NFTokenID },
|
12612
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12613
|
+
],
|
12559
12614
|
options.transactionOptions);
|
12560
12615
|
|
12561
12616
|
console.log('Waiting for the buy offer')
|
@@ -12594,21 +12649,62 @@ class HostClient extends BaseEvernodeClient {
|
|
12594
12649
|
}
|
12595
12650
|
|
12596
12651
|
async updateRegInfo(activeInstanceCount = null, version = null, totalInstanceCount = null, tokenID = null, countryCode = null, cpuMicroSec = null, ramMb = null, diskMb = null, description = null, options = {}) {
|
12597
|
-
|
12652
|
+
// <token_id(32)><country_code(2)><cpu_microsec(4)><ram_mb(4)><disk_mb(4)><total_instance_count(4)><active_instances(4)><description(26)><version(3)>
|
12653
|
+
const memoBuf = Buffer.alloc(HOST_UPDATE_MEMO_SIZE, 0);
|
12654
|
+
if (tokenID)
|
12655
|
+
Buffer.from(tokenID.substr(0, 32), "hex").copy(memoBuf, HOST_UPDATE_TOKEN_ID_MEMO_OFFSET);
|
12656
|
+
if (countryCode)
|
12657
|
+
Buffer.from(countryCode.substr(0, 2), "utf-8").copy(memoBuf, HOST_UPDATE_COUNTRY_CODE_MEMO_OFFSET);
|
12658
|
+
if (cpuMicroSec)
|
12659
|
+
memoBuf.writeUInt32BE(cpuMicroSec, HOST_UPDATE_CPU_MICROSEC_MEMO_OFFSET);
|
12660
|
+
if (ramMb)
|
12661
|
+
memoBuf.writeUInt32BE(ramMb, HOST_UPDATE_RAM_MB_MEMO_OFFSET);
|
12662
|
+
if (diskMb)
|
12663
|
+
memoBuf.writeUInt32BE(diskMb, HOST_UPDATE_DISK_MB_MEMO_OFFSET);
|
12664
|
+
if (totalInstanceCount)
|
12665
|
+
memoBuf.writeUInt32BE(totalInstanceCount, HOST_UPDATE_TOT_INS_COUNT_MEMO_OFFSET);
|
12666
|
+
if (activeInstanceCount)
|
12667
|
+
memoBuf.writeUInt32BE(activeInstanceCount, HOST_UPDATE_ACT_INS_COUNT_MEMO_OFFSET);
|
12668
|
+
if (description)
|
12669
|
+
Buffer.from(description.substr(0, 26), "utf-8").copy(memoBuf, HOST_UPDATE_DESCRIPTION_MEMO_OFFSET);
|
12670
|
+
if (version) {
|
12671
|
+
const components = version.split('.').map(v => parseInt(v));
|
12672
|
+
if (components.length != 3)
|
12673
|
+
throw 'Invalid version format.';
|
12674
|
+
memoBuf.writeUInt8(components[0], HOST_UPDATE_VERSION_MEMO_OFFSET);
|
12675
|
+
memoBuf.writeUInt8(components[1], HOST_UPDATE_VERSION_MEMO_OFFSET + 1);
|
12676
|
+
memoBuf.writeUInt8(components[2], HOST_UPDATE_VERSION_MEMO_OFFSET + 2);
|
12677
|
+
}
|
12678
|
+
|
12679
|
+
// To obtain registration NFT Page Keylet and index.
|
12680
|
+
if (!tokenID)
|
12681
|
+
tokenID = (await this.getRegistrationNft()).NFTokenID;
|
12682
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(tokenID, this.xrplAcc, this.xrplApi);
|
12683
|
+
|
12598
12684
|
return await this.xrplAcc.makePayment(this.registryAddress,
|
12599
12685
|
XrplConstants.MIN_XRP_AMOUNT,
|
12600
12686
|
XrplConstants.XRP,
|
12601
12687
|
null,
|
12602
|
-
[
|
12688
|
+
[
|
12689
|
+
{ type: MemoTypes.HOST_UPDATE_INFO, format: MemoFormats.HEX, data: memoBuf.toString('hex') },
|
12690
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12691
|
+
],
|
12603
12692
|
options.transactionOptions);
|
12604
12693
|
}
|
12605
12694
|
|
12606
12695
|
async heartbeat(options = {}) {
|
12696
|
+
// To obtain registration NFT Page Keylet and index.
|
12697
|
+
const regNFT = await this.getRegistrationNft();
|
12698
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(regNFT.NFTokenID, this.xrplAcc, this.xrplApi);
|
12699
|
+
|
12607
12700
|
return this.xrplAcc.makePayment(this.registryAddress,
|
12608
12701
|
XrplConstants.MIN_XRP_AMOUNT,
|
12609
12702
|
XrplConstants.XRP,
|
12610
12703
|
null,
|
12611
|
-
[
|
12704
|
+
[
|
12705
|
+
{ type: MemoTypes.HEARTBEAT, format: "", data: "" },
|
12706
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12707
|
+
],
|
12612
12708
|
options.transactionOptions);
|
12613
12709
|
}
|
12614
12710
|
|
@@ -12692,11 +12788,19 @@ class HostClient extends BaseEvernodeClient {
|
|
12692
12788
|
}
|
12693
12789
|
|
12694
12790
|
async requestRebate(options = {}) {
|
12791
|
+
|
12792
|
+
// To obtain registration NFT Page Keylet and index.
|
12793
|
+
const regNFT = await this.getRegistrationNft();
|
12794
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(regNFT.NFTokenID, this.xrplAcc, this.xrplApi);
|
12795
|
+
|
12695
12796
|
return this.xrplAcc.makePayment(this.registryAddress,
|
12696
12797
|
XrplConstants.MIN_XRP_AMOUNT,
|
12697
12798
|
XrplConstants.XRP,
|
12698
12799
|
null,
|
12699
|
-
[
|
12800
|
+
[
|
12801
|
+
{ type: MemoTypes.HOST_REBATE, format: "", data: "" },
|
12802
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12803
|
+
],
|
12700
12804
|
options.transactionOptions);
|
12701
12805
|
}
|
12702
12806
|
|
@@ -12727,16 +12831,21 @@ class HostClient extends BaseEvernodeClient {
|
|
12727
12831
|
}
|
12728
12832
|
}
|
12729
12833
|
|
12730
|
-
const regNFT = (await this.xrplAcc.getNfts()).find(n => n.URI.startsWith(EvernodeConstants.NFT_PREFIX_HEX) && n.Issuer === this.registryAddress);
|
12731
|
-
|
12732
12834
|
let memoData = Buffer.allocUnsafe(20);
|
12733
12835
|
codec.decodeAccountID(transfereeAddress).copy(memoData);
|
12734
12836
|
|
12837
|
+
// To obtain registration NFT Page Keylet and index.
|
12838
|
+
const regNFT = await this.getRegistrationNft();
|
12839
|
+
const nftPageDataBuf = await EvernodeHelpers.getNFTPageAndLocation(regNFT.NFTokenID, this.xrplAcc, this.xrplApi);
|
12840
|
+
|
12735
12841
|
await this.xrplAcc.makePayment(this.registryAddress,
|
12736
12842
|
XrplConstants.MIN_XRP_AMOUNT,
|
12737
12843
|
XrplConstants.XRP,
|
12738
12844
|
null,
|
12739
|
-
[
|
12845
|
+
[
|
12846
|
+
{ type: MemoTypes.HOST_TRANSFER, format: MemoFormats.HEX, data: memoData.toString('hex') },
|
12847
|
+
{ type: MemoTypes.HOST_REGISTRY_REF, format: MemoFormats.HEX, data: nftPageDataBuf.toString('hex') }
|
12848
|
+
],
|
12740
12849
|
options.transactionOptions);
|
12741
12850
|
|
12742
12851
|
let offer = null;
|
@@ -12768,6 +12877,19 @@ class HostClient extends BaseEvernodeClient {
|
|
12768
12877
|
|
12769
12878
|
await this.xrplAcc.sellNft(offer.index);
|
12770
12879
|
}
|
12880
|
+
|
12881
|
+
async hasPendingTransfer() {
|
12882
|
+
|
12883
|
+
// Check the availability of TRANSFEREE state for this host address.
|
12884
|
+
const stateTransfereeAddrKey = StateHelpers.generateTransfereeAddrStateKey(this.xrplAcc.address);
|
12885
|
+
const stateTransfereeAddrIndex = StateHelpers.getHookStateIndex(this.registryAddress, stateTransfereeAddrKey);
|
12886
|
+
const res = await this.xrplApi.getLedgerEntry(stateTransfereeAddrIndex);
|
12887
|
+
|
12888
|
+
if (res && res?.HookStateData)
|
12889
|
+
return true;
|
12890
|
+
|
12891
|
+
return false;
|
12892
|
+
}
|
12771
12893
|
}
|
12772
12894
|
|
12773
12895
|
module.exports = {
|
@@ -13594,7 +13716,8 @@ const MemoTypes = {
|
|
13594
13716
|
REFUND: 'evnRefund',
|
13595
13717
|
REFUND_REF: 'evnRefundRef',
|
13596
13718
|
DEAD_HOST_PRUNE: 'evnDeadHostPrune',
|
13597
|
-
HOST_REBATE: 'evnHostRebate'
|
13719
|
+
HOST_REBATE: 'evnHostRebate',
|
13720
|
+
HOST_REGISTRY_REF: 'evnHostRegistryRef'
|
13598
13721
|
}
|
13599
13722
|
|
13600
13723
|
const MemoFormats = {
|
@@ -13686,6 +13809,7 @@ module.exports = {
|
|
13686
13809
|
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
13687
13810
|
|
13688
13811
|
const { EvernodeConstants } = __nccwpck_require__(9849);
|
13812
|
+
const NFT_PAGE_LEDGER_ENTRY_TYPE_HEX = '0050';
|
13689
13813
|
|
13690
13814
|
class EvernodeHelpers {
|
13691
13815
|
static async getLeaseOffers(xrplAcc) {
|
@@ -13694,6 +13818,36 @@ class EvernodeHelpers {
|
|
13694
13818
|
const nftOffers = (await xrplAcc.getNftOffers())?.filter(offer => (offer.Flags == 1 && hostTokenIDs.includes(offer.NFTokenID))); // Filter only sell offers
|
13695
13819
|
return nftOffers;
|
13696
13820
|
}
|
13821
|
+
|
13822
|
+
static async getNFTPageAndLocation(nfTokenId, xrplAcc, xrplApi, buffer = true) {
|
13823
|
+
|
13824
|
+
const nftPageApprxKeylet = xrplAcc.generateKeylet('nftPage', { nfTokenId: nfTokenId });
|
13825
|
+
const nftPageMaxKeylet = xrplAcc.generateKeylet('nftPageMax');
|
13826
|
+
// Index is the last 32 bytes of the Keylet (Last 64 HEX characters).
|
13827
|
+
let page = await xrplApi.getLedgerEntry(nftPageMaxKeylet.substring(4, 68));
|
13828
|
+
while (page?.PreviousPageMin) {
|
13829
|
+
// Compare the low 96 bits. (Last 24 HEX characters).
|
13830
|
+
if (Number('0x' + page.index.substring(40, 64)) >= Number('0x' + nftPageApprxKeylet.substring(40, 64))) {
|
13831
|
+
// Check the existence of the NFToken
|
13832
|
+
let token = page.NFTokens.find(n => n.NFToken.NFTokenID == nfTokenId);
|
13833
|
+
if (!token) {
|
13834
|
+
page = await xrplApi.getLedgerEntry(page.PreviousPageMin);
|
13835
|
+
}
|
13836
|
+
else
|
13837
|
+
break;
|
13838
|
+
}
|
13839
|
+
}
|
13840
|
+
|
13841
|
+
const nftPageInfo = page.NFTokens.map((n, loc) => { return { NFTPage: NFT_PAGE_LEDGER_ENTRY_TYPE_HEX + page.index, NFTokenID: n.NFToken.NFTokenID, location: loc } }).find(n => n.NFTokenID == nfTokenId);
|
13842
|
+
if (buffer) {
|
13843
|
+
let locBuf = Buffer.allocUnsafe(2);
|
13844
|
+
locBuf.writeUInt16BE(nftPageInfo.location);
|
13845
|
+
// <NFT_PAGE_KEYLET(34 bytes)><LOCATION(2 bytes)>
|
13846
|
+
return Buffer.concat([Buffer.from(nftPageInfo.NFTPage, "hex"), locBuf]);
|
13847
|
+
}
|
13848
|
+
|
13849
|
+
return nftPageInfo;
|
13850
|
+
}
|
13697
13851
|
}
|
13698
13852
|
|
13699
13853
|
module.exports = {
|
@@ -14110,7 +14264,7 @@ const HOST_CPU_SPEED_OFFSET = 62;
|
|
14110
14264
|
const HOST_CPU_MICROSEC_OFFSET = 64;
|
14111
14265
|
const HOST_RAM_MB_OFFSET = 68;
|
14112
14266
|
const HOST_DISK_MB_OFFSET = 72;
|
14113
|
-
const
|
14267
|
+
const HOST_EMAIL_ADDRESS_OFFSET = 76;
|
14114
14268
|
|
14115
14269
|
const PREV_HOST_ADDRESS_OFFSET = 0;
|
14116
14270
|
const TRANSFER_LEDGER_IDX_OFFSET = 20;
|
@@ -14137,6 +14291,7 @@ const HOST_ADDR_KEY_ZERO_COUNT = 8;
|
|
14137
14291
|
const TRANSFEREE_ADDR_KEY_ZERO_COUNT = 8;
|
14138
14292
|
const HOOK_STATE_LEDGER_TYPE_PREFIX = 118; // Decimal value of ASCII 'v'
|
14139
14293
|
const PENDING_TRANSFER = 1;
|
14294
|
+
const HOST_EMAIL_ADDRESS_LEN = 40;
|
14140
14295
|
|
14141
14296
|
class StateHelpers {
|
14142
14297
|
static StateTypes = {
|
@@ -14187,7 +14342,9 @@ class StateHelpers {
|
|
14187
14342
|
cpuMicrosec: stateDataBuf.readUInt32BE(HOST_CPU_MICROSEC_OFFSET),
|
14188
14343
|
ramMb: stateDataBuf.readUInt32BE(HOST_RAM_MB_OFFSET),
|
14189
14344
|
diskMb: stateDataBuf.readUInt32BE(HOST_DISK_MB_OFFSET),
|
14190
|
-
email: (stateDataBuf.length >
|
14345
|
+
email: (stateDataBuf.length > HOST_EMAIL_ADDRESS_OFFSET ?
|
14346
|
+
stateDataBuf.slice(HOST_EMAIL_ADDRESS_OFFSET, HOST_EMAIL_ADDRESS_OFFSET + HOST_EMAIL_ADDRESS_LEN).toString().toString().replace(/\0/g, '') :
|
14347
|
+
"")
|
14191
14348
|
}
|
14192
14349
|
}
|
14193
14350
|
|
@@ -14738,18 +14895,27 @@ class XrplAccount {
|
|
14738
14895
|
#subscribed = false;
|
14739
14896
|
#txStreamHandler;
|
14740
14897
|
|
14741
|
-
constructor(address, secret = null, options = {}) {
|
14898
|
+
constructor(address = null, secret = null, options = {}) {
|
14899
|
+
if (!address && !secret)
|
14900
|
+
throw "Both address and secret cannot be empty";
|
14901
|
+
|
14902
|
+
this.address = address;
|
14903
|
+
this.secret = secret;
|
14742
14904
|
this.xrplApi = options.xrplApi || DefaultValues.xrplApi;
|
14743
14905
|
|
14744
14906
|
if (!this.xrplApi)
|
14745
14907
|
throw "XrplAccount: xrplApi not specified.";
|
14746
14908
|
|
14747
|
-
this.address
|
14748
|
-
|
14749
|
-
this.secret = secret;
|
14750
|
-
if (this.secret) {
|
14909
|
+
if (!this.address && this.secret) {
|
14751
14910
|
this.wallet = xrpl.Wallet.fromSeed(this.secret);
|
14752
|
-
this.address= this.wallet.classicAddress;
|
14911
|
+
this.address = this.wallet.classicAddress;
|
14912
|
+
} else if (this.secret) {
|
14913
|
+
const keypair = kp.deriveKeypair(this.secret);
|
14914
|
+
const derivedPubKeyAddress = kp.deriveAddress(keypair.publicKey);
|
14915
|
+
if (this.address == derivedPubKeyAddress)
|
14916
|
+
this.wallet = xrpl.Wallet.fromSeed(this.secret);
|
14917
|
+
else
|
14918
|
+
this.wallet = xrpl.Wallet.fromSeed(this.secret, { masterAddress: this.address });
|
14753
14919
|
}
|
14754
14920
|
|
14755
14921
|
this.#txStreamHandler = (eventName, tx, error) => {
|
@@ -14776,6 +14942,10 @@ class XrplAccount {
|
|
14776
14942
|
return kp.deriveKeypair(this.secret);
|
14777
14943
|
}
|
14778
14944
|
|
14945
|
+
async exists() {
|
14946
|
+
return await this.xrplApi.isAccountExists(this.address);
|
14947
|
+
}
|
14948
|
+
|
14779
14949
|
async getInfo() {
|
14780
14950
|
return await this.xrplApi.getAccountInfo(this.address);
|
14781
14951
|
}
|
@@ -14849,6 +15019,10 @@ class XrplAccount {
|
|
14849
15019
|
return await this.xrplApi.getAccountTrx(this.address, { ledger_index_min: minLedgerIndex, ledger_index_max: maxLedgerIndex, forward: isForward });
|
14850
15020
|
}
|
14851
15021
|
|
15022
|
+
async hasValidKeyPair() {
|
15023
|
+
return await this.xrplApi.isValidKeyForAddress(this.wallet.publicKey, this.address);
|
15024
|
+
}
|
15025
|
+
|
14852
15026
|
setAccountFields(fields, options = {}) {
|
14853
15027
|
/**
|
14854
15028
|
* Example for fields
|
@@ -15072,6 +15246,29 @@ class XrplAccount {
|
|
15072
15246
|
return this.#submitAndVerifyTransaction(owner ? { ...tx, Owner: owner } : tx, options);
|
15073
15247
|
}
|
15074
15248
|
|
15249
|
+
generateKeylet(type, data = {}) {
|
15250
|
+
switch (type) {
|
15251
|
+
case 'nftPage': {
|
15252
|
+
const accIdHex = (codec.decodeAccountID(this.address)).toString('hex').toUpperCase();
|
15253
|
+
const tokenPortion = data?.nfTokenId.substr(40, 64);
|
15254
|
+
return '0050' + accIdHex + tokenPortion;
|
15255
|
+
}
|
15256
|
+
|
15257
|
+
case 'nftPageMax': {
|
15258
|
+
const accIdHex = (codec.decodeAccountID(this.address)).toString('hex').toUpperCase();
|
15259
|
+
return '0050' + accIdHex + 'F'.repeat(24);
|
15260
|
+
}
|
15261
|
+
|
15262
|
+
case 'nftPageMin': {
|
15263
|
+
const accIdHex = (codec.decodeAccountID(this.address)).toString('hex').toUpperCase();
|
15264
|
+
return '0050' + accIdHex + '0'.repeat(24);
|
15265
|
+
}
|
15266
|
+
|
15267
|
+
default:
|
15268
|
+
return null;
|
15269
|
+
}
|
15270
|
+
}
|
15271
|
+
|
15075
15272
|
async subscribe() {
|
15076
15273
|
// Subscribe only once. Otherwise event handlers will be duplicated.
|
15077
15274
|
if (this.#subscribed)
|
@@ -15407,6 +15604,17 @@ class XrplApi {
|
|
15407
15604
|
return derivedPubKeyAddress === address || (regularKey && derivedPubKeyAddress === regularKey);
|
15408
15605
|
}
|
15409
15606
|
|
15607
|
+
async isAccountExists(address) {
|
15608
|
+
try {
|
15609
|
+
await this.#client.request({ command: 'account_info', account: address });
|
15610
|
+
return true;
|
15611
|
+
}
|
15612
|
+
catch (e) {
|
15613
|
+
if (e.data.error === 'actNotFound') return false;
|
15614
|
+
else throw e;
|
15615
|
+
}
|
15616
|
+
}
|
15617
|
+
|
15410
15618
|
async getAccountInfo(address) {
|
15411
15619
|
const resp = (await this.#client.request({ command: 'account_info', account: address }));
|
15412
15620
|
return resp?.result?.account_data;
|
@@ -15451,8 +15659,15 @@ class XrplApi {
|
|
15451
15659
|
}
|
15452
15660
|
|
15453
15661
|
async getLedgerEntry(index, options) {
|
15454
|
-
|
15455
|
-
|
15662
|
+
try {
|
15663
|
+
const resp = (await this.#client.request({ command: 'ledger_entry', index: index, ledger_index: "validated", ...options }));
|
15664
|
+
return resp?.result?.node;
|
15665
|
+
|
15666
|
+
} catch (e) {
|
15667
|
+
if (e?.data?.error === 'entryNotFound')
|
15668
|
+
return null;
|
15669
|
+
throw e;
|
15670
|
+
}
|
15456
15671
|
}
|
15457
15672
|
|
15458
15673
|
async submitAndVerify(tx, options) {
|