evernode-js-client 0.4.45 → 0.4.48

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/index.js +81 -21
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -11716,6 +11716,7 @@ const { EventEmitter } = __nccwpck_require__(6170);
11716
11716
  const { UtilHelpers } = __nccwpck_require__(6687);
11717
11717
  const { FirestoreHandler } = __nccwpck_require__(9718);
11718
11718
  const { XflHelpers } = __nccwpck_require__(3243);
11719
+ const { StateHelpers } = __nccwpck_require__(3860);
11719
11720
 
11720
11721
  class BaseEvernodeClient {
11721
11722
 
@@ -11802,13 +11803,11 @@ class BaseEvernodeClient {
11802
11803
 
11803
11804
  async getHookStates() {
11804
11805
  const regAcc = new XrplAccount(this.registryAddress, null, { xrplApi: this.xrplApi });
11805
- const hookNamespaces = (await regAcc.getInfo())?.HookNamespaces;
11806
- if (hookNamespaces) {
11807
- const configs = await regAcc.getNamespaceEntries(hookNamespaces[0]);
11806
+ const configs = await regAcc.getNamespaceEntries(EvernodeConstants.HOOK_NAMESPACE);
11807
+
11808
+ if (configs)
11808
11809
  return configs.filter(c => c.LedgerEntryType === 'HookState').map(c => { return { key: c.HookStateKey, data: c.HookStateData } });
11809
- }
11810
11810
  return [];
11811
-
11812
11811
  }
11813
11812
 
11814
11813
  async getMoment(ledgerIndex = null) {
@@ -12060,6 +12059,40 @@ class BaseEvernodeClient {
12060
12059
  return null;
12061
12060
  }
12062
12061
 
12062
+ // To get Host details from Hook States.
12063
+ async getHostInfo(hostAddress = this.xrplAcc.address) {
12064
+ try {
12065
+ const addrStateKey = StateHelpers.generateHostAddrStateKey(hostAddress);
12066
+ const addrStateIndex = StateHelpers.getHookStateIndex(this.registryAddress, addrStateKey);
12067
+ const addrLedgerEntry = await this.xrplApi.getLedgerEntry(addrStateIndex);
12068
+ const addrStateData = addrLedgerEntry?.HookStateData;
12069
+ if (addrStateData) {
12070
+ const addrStateDecoded = StateHelpers.decodeHostAddressState(Buffer.from(addrStateKey, 'hex'), Buffer.from(addrStateData, 'hex'));
12071
+ const curMomentStartIdx = await this.getMomentStartIndex();
12072
+ addrStateDecoded.active = (addrStateDecoded.lastHeartbeatLedger > (this.config.hostHeartbeatFreq * this.config.momentSize) ?
12073
+ (addrStateDecoded.lastHeartbeatLedger >= (curMomentStartIdx - (this.config.hostHeartbeatFreq * this.config.momentSize))) :
12074
+ (addrStateDecoded.lastHeartbeatLedger > 0))
12075
+
12076
+ const nftIdStatekey = StateHelpers.generateTokenIdStateKey(addrStateDecoded.nfTokenId);
12077
+ const nftIdStateIndex = StateHelpers.getHookStateIndex(this.registryAddress, nftIdStatekey);
12078
+ const nftIdLedgerEntry = await this.xrplApi.getLedgerEntry(nftIdStateIndex);
12079
+
12080
+ const nftIdStateData = nftIdLedgerEntry?.HookStateData;
12081
+ if (nftIdStateData) {
12082
+ const nftIdStateDecoded = StateHelpers.decodeTokenIdState(Buffer.from(nftIdStateData, 'hex'));
12083
+ return {...addrStateDecoded, ...nftIdStateDecoded};
12084
+ }
12085
+ }
12086
+ }
12087
+ catch (e) {
12088
+ // If the exeption is entryNotFound from Rippled there's no entry for the host, So return null.
12089
+ if (e?.data?.error !== 'entryNotFound')
12090
+ throw e;
12091
+ }
12092
+
12093
+ return null;
12094
+ }
12095
+
12063
12096
  // To fetch records from host collection in Firestore database. (Pagination is applied - default page size :20)
12064
12097
  async getHosts(filters = null, pageSize = null, nextPageToken = null) {
12065
12098
  const hosts = await this.#firestoreHandler.getHosts(filters, pageSize, nextPageToken);
@@ -12165,9 +12198,8 @@ class HostClient extends BaseEvernodeClient {
12165
12198
  // Check whether we own an evernode host token.
12166
12199
  const nft = await this.getRegistrationNft();
12167
12200
  if (nft) {
12168
- const host = await this.getHosts({ nfTokenId: nft.NFTokenID });
12169
- if (host && host.length == 1)
12170
- return host[0];
12201
+ const host = await this.getHostInfo();
12202
+ return (host?.nfTokenId == nft.NFTokenID) ? host : null;
12171
12203
  }
12172
12204
 
12173
12205
  return null;
@@ -12266,10 +12298,10 @@ class HostClient extends BaseEvernodeClient {
12266
12298
  // from the client-side in order to complete the registration.
12267
12299
  const regNft = await this.getRegistrationNft();
12268
12300
  if (!regNft) {
12269
- const regInfo = await this.getHosts({ address: this.xrplAcc.address });
12270
- if (regInfo.length !== 0) {
12301
+ const regInfo = await this.getHostInfo(this.xrplAcc.address);
12302
+ if (regInfo) {
12271
12303
  const registryAcc = new XrplAccount(this.registryAddress, null, { xrplApi: this.xrplApi });
12272
- const sellOffer = (await registryAcc.getNftOffers()).find(o => o.NFTokenID == regInfo[0].nfTokenId);
12304
+ const sellOffer = (await registryAcc.getNftOffers()).find(o => o.NFTokenID == regInfo.nfTokenId);
12273
12305
  if (sellOffer) {
12274
12306
  await this.xrplAcc.buyNft(sellOffer.index);
12275
12307
  console.log("Registration was successfully completed after acquiring the NFT.");
@@ -12516,7 +12548,7 @@ class RegistryClient extends BaseEvernodeClient {
12516
12548
  while (currentPageToken) {
12517
12549
  nextHosts = await this.getHosts(null, null, currentPageToken);
12518
12550
  fullHostList = fullHostList.concat(nextHosts.nextPageToken ? nextHosts.data : nextHosts);
12519
- currentPageToken = nextHosts.nextPageToken;
12551
+ currentPageToken = nextHosts.nextPageToken;
12520
12552
  }
12521
12553
  } else {
12522
12554
  fullHostList = fullHostList.concat(hosts);
@@ -12604,10 +12636,10 @@ class TenantClient extends BaseEvernodeClient {
12604
12636
  throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
12605
12637
 
12606
12638
  // Check whether active.
12607
- const hosts = await this.getHosts({ address: host.address });
12608
- if (!hosts || !hosts.length)
12639
+ const hostInfo = await this.getHostInfo(host.address);
12640
+ if (!hostInfo)
12609
12641
  throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
12610
- else if (!hosts[0].active)
12642
+ else if (!hostInfo.active)
12611
12643
  throw { reason: ErrorReasons.HOST_INACTIVE, error: "Host is not active." };
12612
12644
 
12613
12645
  return host;
@@ -12620,7 +12652,7 @@ class TenantClient extends BaseEvernodeClient {
12620
12652
 
12621
12653
  // Attempt to get first available offer, if offer is not specified in options.
12622
12654
  if (!selectedOfferIndex) {
12623
- const nftOffers = EvernodeHelpers.getLeaseOffers(hostAcc);
12655
+ const nftOffers = await EvernodeHelpers.getLeaseOffers(hostAcc);
12624
12656
  selectedOfferIndex = nftOffers && nftOffers[0] && nftOffers[0].index;
12625
12657
 
12626
12658
  if (!selectedOfferIndex)
@@ -12751,7 +12783,7 @@ module.exports = {
12751
12783
  /***/ ((module) => {
12752
12784
 
12753
12785
  const DefaultValues = {
12754
- registryAddress: 'rDPqJv7zu6DfeXexAYseABNM2hT2j2rpHv',
12786
+ registryAddress: 'raaFre81618XegCrzTzVotAmarBcqNSAvK',
12755
12787
  rippledServer: 'wss://hooks-testnet-v2.xrpl-labs.com',
12756
12788
  xrplApi: null,
12757
12789
  stateIndexId: 'evernodeindex'
@@ -13142,7 +13174,8 @@ module.exports = {
13142
13174
  const EvernodeConstants = {
13143
13175
  EVR: 'EVR',
13144
13176
  NFT_PREFIX_HEX: '657672686F7374', // evrhost
13145
- LEASE_NFT_PREFIX_HEX: '6576726C65617365' // evrlease
13177
+ LEASE_NFT_PREFIX_HEX: '6576726C65617365', // evrlease
13178
+ HOOK_NAMESPACE: '01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0'
13146
13179
  }
13147
13180
 
13148
13181
  const MemoTypes = {
@@ -13587,10 +13620,11 @@ module.exports = {
13587
13620
 
13588
13621
  const codec = __nccwpck_require__(597);
13589
13622
  const { Buffer } = __nccwpck_require__(4300);
13590
- const { HookStateKeys } = __nccwpck_require__(9849);
13623
+ const { HookStateKeys, EvernodeConstants } = __nccwpck_require__(9849);
13591
13624
  const { XflHelpers } = __nccwpck_require__(3243);
13625
+ const crypto = __nccwpck_require__(6113);
13592
13626
 
13593
- const NFTOKEN_PREFIX = '00080000';
13627
+ const NFTOKEN_PREFIX = '00000000';
13594
13628
 
13595
13629
  const HOST_TOKEN_ID_OFFSET = 0;
13596
13630
  const HOST_COUNTRY_CODE_OFFSET = 32;
@@ -13618,6 +13652,7 @@ const STATE_KEY_TYPES = {
13618
13652
 
13619
13653
  const EVERNODE_PREFIX = 'EVR';
13620
13654
  const HOST_ADDR_KEY_ZERO_COUNT = 8;
13655
+ const HOOK_STATE_LEDGER_TYPE_PREFIX = 118; // Decimal value of ASCII 'v'
13621
13656
 
13622
13657
  class StateHelpers {
13623
13658
  static StateTypes = {
@@ -13645,7 +13680,7 @@ class StateHelpers {
13645
13680
  static decodeTokenIdState(stateDataBuf) {
13646
13681
  return {
13647
13682
  address: codec.encodeAccountID(stateDataBuf.slice(HOST_ADDRESS_OFFSET, HOST_CPU_MODEL_NAME_OFFSET)),
13648
- cpuModelName: stateDataBuf.slice(HOST_CPU_MODEL_NAME_OFFSET, HOST_CPU_COUNT_OFFSET).toString(),
13683
+ cpuModelName: stateDataBuf.slice(HOST_CPU_MODEL_NAME_OFFSET, HOST_CPU_COUNT_OFFSET).toString().replace(/\x00+$/, ''), // Remove trailing \x00 characters.
13649
13684
  cpuCount: stateDataBuf.readUInt16BE(HOST_CPU_COUNT_OFFSET),
13650
13685
  cpuMHz: stateDataBuf.readUInt16BE(HOST_CPU_SPEED_OFFSET),
13651
13686
  cpuMicrosec: stateDataBuf.readUInt32BE(HOST_CPU_MICROSEC_OFFSET),
@@ -13795,6 +13830,26 @@ class StateHelpers {
13795
13830
  const stateKeyBuf = Buffer.concat([Buffer.from(EVERNODE_PREFIX, "utf-8"), buf, addrBuf]);
13796
13831
  return stateKeyBuf.toString('hex').toUpperCase();
13797
13832
  }
13833
+
13834
+ static getHookStateIndex(hookAccount, stateKey, hookNamespace = EvernodeConstants.HOOK_NAMESPACE) {
13835
+ const typeBuf = Buffer.allocUnsafe(2);
13836
+ typeBuf.writeInt16BE(HOOK_STATE_LEDGER_TYPE_PREFIX);
13837
+
13838
+ const accIdBuf = codec.decodeAccountID(hookAccount);
13839
+ const stateKeyBuf = Buffer.from(stateKey, 'hex');
13840
+ const namespaceBuf = Buffer.from(hookNamespace, 'hex');
13841
+
13842
+ let hash = crypto.createHash('sha512');
13843
+
13844
+ let data = hash.update(typeBuf);
13845
+ data = hash.update(accIdBuf);
13846
+ data = hash.update(stateKeyBuf);
13847
+ data = hash.update(namespaceBuf);
13848
+
13849
+ const digest = data.digest('hex');
13850
+ // Get the first 32 bytes of hash.
13851
+ return digest.substring(0, 64).toUpperCase();
13852
+ }
13798
13853
  }
13799
13854
 
13800
13855
  module.exports = {
@@ -14757,6 +14812,11 @@ class XrplApi {
14757
14812
  return [];
14758
14813
  }
14759
14814
 
14815
+ async getLedgerEntry(index, options) {
14816
+ const resp = (await this.#client.request({ command: 'ledger_entry', index: index, ledger_index: "validated", ...options }));
14817
+ return resp?.result?.node;
14818
+ }
14819
+
14760
14820
  async submitAndVerify(tx, options) {
14761
14821
  return await this.#client.submitAndWait(tx, options);
14762
14822
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evernode-js-client",
3
- "version": "0.4.45",
3
+ "version": "0.4.48",
4
4
  "dependencies": {
5
5
  "elliptic": "6.5.4",
6
6
  "ripple-address-codec": "4.2.0",