evernode-js-client 0.4.46 → 0.4.50

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 +154 -26
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -11708,7 +11708,7 @@ const codec = __nccwpck_require__(597);
11708
11708
  const { Buffer } = __nccwpck_require__(4300);
11709
11709
  const { XrplApi } = __nccwpck_require__(1850);
11710
11710
  const { XrplAccount } = __nccwpck_require__(9329);
11711
- const { XrplApiEvents } = __nccwpck_require__(3307);
11711
+ const { XrplApiEvents, XrplConstants } = __nccwpck_require__(3307);
11712
11712
  const { EvernodeEvents, MemoTypes, MemoFormats, EvernodeConstants, HookStateKeys } = __nccwpck_require__(9849);
11713
11713
  const { DefaultValues } = __nccwpck_require__(8262);
11714
11714
  const { EncryptionHelper } = __nccwpck_require__(4832);
@@ -12055,23 +12055,52 @@ class BaseEvernodeClient {
12055
12055
  }
12056
12056
  }
12057
12057
  }
12058
+ else if (tx.Memos.length >= 1 &&
12059
+ tx.Memos[0].type === MemoTypes.DEAD_HOST_PRUNE && tx.Memos[0].format === MemoFormats.HEX && tx.Memos[0].data) {
12060
+
12061
+ const addrsBuf = Buffer.from(tx.Memos[0].data, 'hex');
12062
+
12063
+ return {
12064
+ name: EvernodeEvents.DeadHostPrune,
12065
+ data: {
12066
+ transaction: tx,
12067
+ host: codec.encodeAccountID(addrsBuf)
12068
+ }
12069
+ }
12070
+ }
12058
12071
 
12059
12072
  return null;
12060
12073
  }
12061
12074
 
12062
12075
  // To get Host details from Hook States.
12063
12076
  async getHostInfo(hostAddress = this.xrplAcc.address) {
12064
- const hostAddrStatekey = StateHelpers.generateHostAddrStateKey(hostAddress);
12065
- const stateLedgerIndex = StateHelpers.getHookStateIndex(this.registryAddress, hostAddrStatekey);
12066
- const ledgerEntry = await this.xrplApi.getLedgerEntry(stateLedgerIndex);
12067
- const curMomentStartIdx = await this.getMomentStartIndex();
12068
- if (ledgerEntry?.HookStateData) {
12069
- const hostAddrStateData = ledgerEntry.HookStateData;
12070
- const hostInfo = StateHelpers.decodeHostAddressState(Buffer.from(hostAddrStatekey, 'hex'), Buffer.from(hostAddrStateData, 'hex'));
12071
- hostInfo.active = (hostInfo.lastHeartbeatLedger > (this.config.hostHeartbeatFreq * this.config.momentSize) ?
12072
- (hostInfo.lastHeartbeatLedger >= (curMomentStartIdx - (this.config.hostHeartbeatFreq * this.config.momentSize))) :
12073
- (hostInfo.lastHeartbeatLedger > 0))
12074
- return hostInfo;
12077
+ try {
12078
+ const addrStateKey = StateHelpers.generateHostAddrStateKey(hostAddress);
12079
+ const addrStateIndex = StateHelpers.getHookStateIndex(this.registryAddress, addrStateKey);
12080
+ const addrLedgerEntry = await this.xrplApi.getLedgerEntry(addrStateIndex);
12081
+ const addrStateData = addrLedgerEntry?.HookStateData;
12082
+ if (addrStateData) {
12083
+ const addrStateDecoded = StateHelpers.decodeHostAddressState(Buffer.from(addrStateKey, 'hex'), Buffer.from(addrStateData, 'hex'));
12084
+ const curMomentStartIdx = await this.getMomentStartIndex();
12085
+ addrStateDecoded.active = (addrStateDecoded.lastHeartbeatLedger > (this.config.hostHeartbeatFreq * this.config.momentSize) ?
12086
+ (addrStateDecoded.lastHeartbeatLedger >= (curMomentStartIdx - (this.config.hostHeartbeatFreq * this.config.momentSize))) :
12087
+ (addrStateDecoded.lastHeartbeatLedger > 0))
12088
+
12089
+ const nftIdStatekey = StateHelpers.generateTokenIdStateKey(addrStateDecoded.nfTokenId);
12090
+ const nftIdStateIndex = StateHelpers.getHookStateIndex(this.registryAddress, nftIdStatekey);
12091
+ const nftIdLedgerEntry = await this.xrplApi.getLedgerEntry(nftIdStateIndex);
12092
+
12093
+ const nftIdStateData = nftIdLedgerEntry?.HookStateData;
12094
+ if (nftIdStateData) {
12095
+ const nftIdStateDecoded = StateHelpers.decodeTokenIdState(Buffer.from(nftIdStateData, 'hex'));
12096
+ return { ...addrStateDecoded, ...nftIdStateDecoded };
12097
+ }
12098
+ }
12099
+ }
12100
+ catch (e) {
12101
+ // If the exeption is entryNotFound from Rippled there's no entry for the host, So return null.
12102
+ if (e?.data?.error !== 'entryNotFound')
12103
+ throw e;
12075
12104
  }
12076
12105
 
12077
12106
  return null;
@@ -12129,6 +12158,22 @@ class BaseEvernodeClient {
12129
12158
 
12130
12159
  return fullHostList;
12131
12160
  }
12161
+
12162
+ // To prune an inactive host/
12163
+ async pruneDeadHost(hostAddress) {
12164
+ if (this.xrplAcc.address === this.registryAddress)
12165
+ throw 'Invalid function call';
12166
+
12167
+ let memoData = Buffer.allocUnsafe(20);
12168
+ codec.decodeAccountID(hostAddress).copy(memoData);
12169
+
12170
+ await this.xrplAcc.makePayment(this.registryAddress,
12171
+ XrplConstants.MIN_XRP_AMOUNT,
12172
+ XrplConstants.XRP,
12173
+ null,
12174
+ [{ type: MemoTypes.DEAD_HOST_PRUNE, format: MemoFormats.HEX, data: memoData.toString('hex') }]);
12175
+
12176
+ }
12132
12177
  }
12133
12178
 
12134
12179
  module.exports = {
@@ -12513,7 +12558,8 @@ const RegistryEvents = {
12513
12558
  HostRegUpdated: EvernodeEvents.HostRegUpdated,
12514
12559
  RegistryInitialized: EvernodeEvents.RegistryInitialized,
12515
12560
  Heartbeat: EvernodeEvents.Heartbeat,
12516
- HostPostDeregistered: EvernodeEvents.HostPostDeregistered
12561
+ HostPostDeregistered: EvernodeEvents.HostPostDeregistered,
12562
+ DeadHostPrune: EvernodeEvents.DeadHostPrune
12517
12563
  }
12518
12564
 
12519
12565
  class RegistryClient extends BaseEvernodeClient {
@@ -12621,9 +12667,9 @@ class TenantClient extends BaseEvernodeClient {
12621
12667
 
12622
12668
  // Check whether active.
12623
12669
  const hostInfo = await this.getHostInfo(host.address);
12624
- if (hostInfo)
12670
+ if (!hostInfo)
12625
12671
  throw { reason: ErrorReasons.HOST_INVALID, error: "Host is not registered." };
12626
- else if (hostInfo.active)
12672
+ else if (!hostInfo.active)
12627
12673
  throw { reason: ErrorReasons.HOST_INACTIVE, error: "Host is not active." };
12628
12674
 
12629
12675
  return host;
@@ -13178,7 +13224,8 @@ const MemoTypes = {
13178
13224
  EXTEND_REF: 'evnExtendRef',
13179
13225
  REGISTRY_INIT: 'evnInitialize',
13180
13226
  REFUND: 'evnRefund',
13181
- REFUND_REF: 'evnRefundRef'
13227
+ REFUND_REF: 'evnRefundRef',
13228
+ DEAD_HOST_PRUNE: 'evnDeadHostPrune'
13182
13229
  }
13183
13230
 
13184
13231
  const MemoFormats = {
@@ -13216,11 +13263,15 @@ const HookStateKeys = {
13216
13263
  HOST_HEARTBEAT_FREQ: "4556520100000000000000000000000000000000000000000000000000000006",
13217
13264
  PURCHASER_TARGET_PRICE: "4556520100000000000000000000000000000000000000000000000000000007",
13218
13265
  LEASE_ACQUIRE_WINDOW: "4556520100000000000000000000000000000000000000000000000000000008",
13266
+ REWARD_CONFIGURATION: "4556520100000000000000000000000000000000000000000000000000000009",
13267
+ MAX_TOLERABLE_DOWNTIME: "455652010000000000000000000000000000000000000000000000000000000A",
13268
+
13219
13269
  // Singleton
13220
13270
  HOST_COUNT: "4556523200000000000000000000000000000000000000000000000000000000",
13221
13271
  MOMENT_BASE_IDX: "4556523300000000000000000000000000000000000000000000000000000000",
13222
13272
  HOST_REG_FEE: "4556523400000000000000000000000000000000000000000000000000000000",
13223
13273
  MAX_REG: "4556523500000000000000000000000000000000000000000000000000000000",
13274
+ REWARD_INFO: "4556523600000000000000000000000000000000000000000000000000000000",
13224
13275
 
13225
13276
  // Prefixes
13226
13277
  PREFIX_HOST_TOKENID: "45565202",
@@ -13240,7 +13291,8 @@ const EvernodeEvents = {
13240
13291
  ExtendError: "ExtendError",
13241
13292
  HostRegUpdated: "HostRegUpdated",
13242
13293
  HostReRegistered: "HostReRegistered",
13243
- RegistryInitialized: "RegistryInitialized"
13294
+ RegistryInitialized: "RegistryInitialized",
13295
+ DeadHostPrune: "DeadHostPrune"
13244
13296
  }
13245
13297
 
13246
13298
  module.exports = {
@@ -13313,6 +13365,13 @@ class FirestoreHandler {
13313
13365
  case 'floatValue':
13314
13366
  parsed = parseFloat(value[type]);
13315
13367
  break;
13368
+ case 'mapValue':
13369
+ parsed = {};
13370
+ for (const [subKey, subValue] of Object.entries(value[type].fields)) {
13371
+ const field = this.#parseValue(subKey, subValue);
13372
+ parsed[field.key] = field.value;
13373
+ }
13374
+ break;
13316
13375
  default:
13317
13376
  parsed = value[type];
13318
13377
  break;
@@ -13520,9 +13579,32 @@ class FirestoreHandler {
13520
13579
  convertValue(key, value) {
13521
13580
  // Convert camelCase to snake_case.
13522
13581
  const uKey = key.replace(/([A-Z])/g, function (g) { return `_${g[0].toLocaleLowerCase()}`; });
13523
- const type = `${typeof value !== 'number' ? 'string' : (value % 1 > 0 ? 'float' : 'integer')}Value`;
13582
+ let val = {};
13583
+ let type
13584
+ switch (typeof value) {
13585
+ case 'number':
13586
+ type = (value % 1 > 0 ? 'float' : 'integer');
13587
+ val = value;
13588
+ break;
13589
+ case 'object':
13590
+ type = 'map';
13591
+ val = {
13592
+ fields: {}
13593
+ }
13594
+ // Prepare the firestore write body with the given data object.
13595
+ for (const [subKey, subValue] of Object.entries(value)) {
13596
+ const field = this.convertValue(subKey, subValue);
13597
+ val.fields[field.key] = field.value;
13598
+ }
13599
+ break;
13600
+ default:
13601
+ type = 'string';
13602
+ val = value;
13603
+ break;
13604
+ }
13605
+ type = `${type}Value`;
13524
13606
  let obj = {};
13525
- obj[type] = value;
13607
+ obj[type] = val;
13526
13608
  return { key: uKey, value: obj };
13527
13609
  }
13528
13610
 
@@ -13608,7 +13690,18 @@ const { HookStateKeys, EvernodeConstants } = __nccwpck_require__(9849);
13608
13690
  const { XflHelpers } = __nccwpck_require__(3243);
13609
13691
  const crypto = __nccwpck_require__(6113);
13610
13692
 
13611
- const NFTOKEN_PREFIX = '00080000';
13693
+ const NFTOKEN_PREFIX = '00000000';
13694
+
13695
+ const EPOCH_OFFSET = 0;
13696
+ const SAVED_MOMENT_OFFSET = 1;
13697
+ const PREV_MOMENT_ACTIVE_HOST_COUNT_OFFSET = 5;
13698
+ const CUR_MOMENT_ACTIVE_HOST_COUNT_OFFSET = 9;
13699
+ const EPOCH_POOL_OFFSET = 13;
13700
+
13701
+ const EPOCH_COUNT_OFFSET = 0;
13702
+ const FIRST_EPOCH_REWARD_QUOTA_OFFSET = 1;
13703
+ const EPOCH_REWARD_AMOUNT_OFFSET = 5;
13704
+ const REWARD_START_MOMENT_OFFSET = 9;
13612
13705
 
13613
13706
  const HOST_TOKEN_ID_OFFSET = 0;
13614
13707
  const HOST_COUNTRY_CODE_OFFSET = 32;
@@ -13664,7 +13757,7 @@ class StateHelpers {
13664
13757
  static decodeTokenIdState(stateDataBuf) {
13665
13758
  return {
13666
13759
  address: codec.encodeAccountID(stateDataBuf.slice(HOST_ADDRESS_OFFSET, HOST_CPU_MODEL_NAME_OFFSET)),
13667
- cpuModelName: stateDataBuf.slice(HOST_CPU_MODEL_NAME_OFFSET, HOST_CPU_COUNT_OFFSET).toString(),
13760
+ cpuModelName: stateDataBuf.slice(HOST_CPU_MODEL_NAME_OFFSET, HOST_CPU_COUNT_OFFSET).toString().replace(/\x00+$/, ''), // Remove trailing \x00 characters.
13668
13761
  cpuCount: stateDataBuf.readUInt16BE(HOST_CPU_COUNT_OFFSET),
13669
13762
  cpuMHz: stateDataBuf.readUInt16BE(HOST_CPU_SPEED_OFFSET),
13670
13763
  cpuMicrosec: stateDataBuf.readUInt32BE(HOST_CPU_MICROSEC_OFFSET),
@@ -13747,6 +13840,38 @@ class StateHelpers {
13747
13840
  value: val
13748
13841
  }
13749
13842
  }
13843
+ else if (Buffer.from(HookStateKeys.REWARD_CONFIGURATION, 'hex').compare(stateKey) === 0) {
13844
+ return {
13845
+ type: this.StateTypes.CONFIGURATION,
13846
+ key: hexKey,
13847
+ value: {
13848
+ epochCount: stateData.readUInt8(EPOCH_COUNT_OFFSET),
13849
+ firstEpochRewardQuota: stateData.readUInt32BE(FIRST_EPOCH_REWARD_QUOTA_OFFSET),
13850
+ epochRewardAmount: stateData.readUInt32BE(EPOCH_REWARD_AMOUNT_OFFSET),
13851
+ rewardStartMoment: stateData.readUInt32BE(REWARD_START_MOMENT_OFFSET)
13852
+ }
13853
+ }
13854
+ }
13855
+ else if (Buffer.from(HookStateKeys.REWARD_INFO, 'hex').compare(stateKey) === 0) {
13856
+ return {
13857
+ type: this.StateTypes.SIGLETON,
13858
+ key: hexKey,
13859
+ value: {
13860
+ epoch: stateData.readUInt8(EPOCH_OFFSET),
13861
+ savedMoment: stateData.readUInt32BE(SAVED_MOMENT_OFFSET),
13862
+ prevMomentActiveHostCount: stateData.readUInt32BE(PREV_MOMENT_ACTIVE_HOST_COUNT_OFFSET),
13863
+ curMomentActiveHostCount: stateData.readUInt32BE(CUR_MOMENT_ACTIVE_HOST_COUNT_OFFSET),
13864
+ epochPool: XflHelpers.toString(stateData.readBigInt64BE(EPOCH_POOL_OFFSET))
13865
+ }
13866
+ }
13867
+ }
13868
+ else if (Buffer.from(HookStateKeys.MAX_TOLERABLE_DOWNTIME, 'hex').compare(stateKey) === 0) {
13869
+ return {
13870
+ type: this.StateTypes.CONFIGURATION,
13871
+ key: hexKey,
13872
+ value: stateData.readUInt16BE()
13873
+ }
13874
+ }
13750
13875
  else
13751
13876
  throw { type: 'Validation Error', message: 'Invalid state key.' };
13752
13877
  }
@@ -13768,7 +13893,8 @@ class StateHelpers {
13768
13893
  else if (Buffer.from(HookStateKeys.HOST_COUNT, 'hex').compare(stateKey) === 0 ||
13769
13894
  Buffer.from(HookStateKeys.MOMENT_BASE_IDX, 'hex').compare(stateKey) === 0 ||
13770
13895
  Buffer.from(HookStateKeys.HOST_REG_FEE, 'hex').compare(stateKey) === 0 ||
13771
- Buffer.from(HookStateKeys.MAX_REG, 'hex').compare(stateKey) === 0) {
13896
+ Buffer.from(HookStateKeys.MAX_REG, 'hex').compare(stateKey) === 0 ||
13897
+ Buffer.from(HookStateKeys.REWARD_INFO, 'hex').compare(stateKey) === 0) {
13772
13898
  return {
13773
13899
  key: hexKey,
13774
13900
  type: this.STATE_TYPES.SIGLETON
@@ -13781,7 +13907,9 @@ class StateHelpers {
13781
13907
  Buffer.from(HookStateKeys.HOST_HEARTBEAT_FREQ, 'hex').compare(stateKey) ||
13782
13908
  Buffer.from(HookStateKeys.MINT_LIMIT, 'hex').compare(stateKey) === 0 ||
13783
13909
  Buffer.from(HookStateKeys.FIXED_REG_FEE, 'hex').compare(stateKey) === 0 ||
13784
- Buffer.from(HookStateKeys.LEASE_ACQUIRE_WINDOW, 'hex').compare(stateKey) === 0) {
13910
+ Buffer.from(HookStateKeys.LEASE_ACQUIRE_WINDOW, 'hex').compare(stateKey) === 0 ||
13911
+ Buffer.from(HookStateKeys.REWARD_CONFIGURATION, 'hex').compare(stateKey) === 0 ||
13912
+ Buffer.from(HookStateKeys.MAX_TOLERABLE_DOWNTIME, 'hex').compare(stateKey) === 0) {
13785
13913
  return {
13786
13914
  key: hexKey,
13787
13915
  type: this.STATE_TYPES.CONFIGURATION
@@ -13807,7 +13935,7 @@ class StateHelpers {
13807
13935
  let buf = Buffer.allocUnsafe(9);
13808
13936
  buf.writeUInt8(STATE_KEY_TYPES.HOST_ADDR);
13809
13937
  for (let i = 0; i < HOST_ADDR_KEY_ZERO_COUNT; i++) {
13810
- buf.writeUInt8(0, i+1);
13938
+ buf.writeUInt8(0, i + 1);
13811
13939
  }
13812
13940
 
13813
13941
  const addrBuf = Buffer.from(codec.decodeAccountID(address), "hex");
@@ -13815,7 +13943,7 @@ class StateHelpers {
13815
13943
  return stateKeyBuf.toString('hex').toUpperCase();
13816
13944
  }
13817
13945
 
13818
- static getHookStateIndex(hookAccount, stateKey, hookNamespace = EvernodeConstants.HOOK_NAMESPACE) {
13946
+ static getHookStateIndex(hookAccount, stateKey, hookNamespace = EvernodeConstants.HOOK_NAMESPACE) {
13819
13947
  const typeBuf = Buffer.allocUnsafe(2);
13820
13948
  typeBuf.writeInt16BE(HOOK_STATE_LEDGER_TYPE_PREFIX);
13821
13949
 
@@ -14798,7 +14926,7 @@ class XrplApi {
14798
14926
 
14799
14927
  async getLedgerEntry(index, options) {
14800
14928
  const resp = (await this.#client.request({ command: 'ledger_entry', index: index, ledger_index: "validated", ...options }));
14801
- return resp?.result?.node;
14929
+ return resp?.result?.node;
14802
14930
  }
14803
14931
 
14804
14932
  async submitAndVerify(tx, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evernode-js-client",
3
- "version": "0.4.46",
3
+ "version": "0.4.50",
4
4
  "dependencies": {
5
5
  "elliptic": "6.5.4",
6
6
  "ripple-address-codec": "4.2.0",