evernode-js-client 0.5.3 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/index.js +106 -6
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -12145,6 +12145,17 @@ class BaseEvernodeClient {
12145
12145
  }
12146
12146
  }
12147
12147
  }
12148
+ else if (tx.Memos.length >= 1 &&
12149
+ tx.Memos[0].type === MemoTypes.HOST_REBATE) {
12150
+
12151
+ return {
12152
+ name: EvernodeEvents.HostRebate,
12153
+ data: {
12154
+ transaction: tx,
12155
+ host: tx.Account
12156
+ }
12157
+ }
12158
+ }
12148
12159
 
12149
12160
  return null;
12150
12161
  }
@@ -12626,6 +12637,15 @@ class HostClient extends BaseEvernodeClient {
12626
12637
  options.transactionOptions);
12627
12638
  }
12628
12639
 
12640
+ async requestRebate(options = {}) {
12641
+ return this.xrplAcc.makePayment(this.registryAddress,
12642
+ XrplConstants.MIN_XRP_AMOUNT,
12643
+ XrplConstants.XRP,
12644
+ null,
12645
+ [{ type: MemoTypes.HOST_REBATE, format: "", data: "" }],
12646
+ options.transactionOptions);
12647
+ }
12648
+
12629
12649
  getLeaseNFTokenIdPrefix() {
12630
12650
  let buf = Buffer.allocUnsafe(24);
12631
12651
  buf.writeUInt16BE(1);
@@ -12633,6 +12653,67 @@ class HostClient extends BaseEvernodeClient {
12633
12653
  codec.decodeAccountID(this.xrplAcc.address).copy(buf, 4);
12634
12654
  return buf.toString('hex');
12635
12655
  }
12656
+
12657
+ async transfer(transfereeAddress = this.xrplAcc.address, options = {}) {
12658
+ if (!(await this.isRegistered()))
12659
+ throw "Host is not registered.";
12660
+
12661
+ const transfereeAcc = new XrplAccount(transfereeAddress, null, { xrplApi: this.xrplApi });
12662
+
12663
+ if (this.xrplAcc.address !== transfereeAddress) {
12664
+ // Find the new transferee also owns an Evernode Host Registration NFT.
12665
+ const nft = (await transfereeAcc.getNfts()).find(n => n.URI.startsWith(EvernodeConstants.NFT_PREFIX_HEX) && n.Issuer === this.registryAddress);
12666
+ if (nft) {
12667
+ // Check whether the token was actually issued from Evernode registry contract.
12668
+ const issuerHex = nft.NFTokenID.substr(8, 40);
12669
+ const issuerAddr = codec.encodeAccountID(Buffer.from(issuerHex, 'hex'));
12670
+ if (issuerAddr == this.registryAddress) {
12671
+ throw "The transferee is already registered in Evernode.";
12672
+ }
12673
+ }
12674
+ }
12675
+
12676
+ const regNFT = (await this.xrplAcc.getNfts()).find(n => n.URI.startsWith(EvernodeConstants.NFT_PREFIX_HEX) && n.Issuer === this.registryAddress);
12677
+
12678
+ let memoData = Buffer.allocUnsafe(20);
12679
+ codec.decodeAccountID(transfereeAddress).copy(memoData);
12680
+
12681
+ await this.xrplAcc.makePayment(this.registryAddress,
12682
+ XrplConstants.MIN_XRP_AMOUNT,
12683
+ XrplConstants.XRP,
12684
+ null,
12685
+ [{ type: MemoTypes.HOST_TRANSFER, format: MemoFormats.HEX, data: memoData.toString('hex') }],
12686
+ options.transactionOptions);
12687
+
12688
+ let offer = null;
12689
+ let attempts = 0;
12690
+ let offerLedgerIndex = 0;
12691
+ const regAcc = new XrplAccount(this.registryAddress, null, { xrplApi: this.xrplApi });
12692
+
12693
+ while (attempts < OFFER_WAIT_TIMEOUT) {
12694
+ offer = (await regAcc.getNftOffers()).find(o => (o.NFTokenID == regNFT.NFTokenID) && (o.Flags === 0));
12695
+ offerLedgerIndex = this.xrplApi.ledgerIndex;
12696
+ if (offer)
12697
+ break;
12698
+ await new Promise(resolve => setTimeout(resolve, 1000));
12699
+ attempts++;
12700
+ }
12701
+ if (!offer)
12702
+ throw 'No buy offer found within timeout.';
12703
+
12704
+ console.log('Accepting the buy offer..');
12705
+
12706
+ // Wait until the next ledger after the offer is created.
12707
+ // Otherwise if the offer accepted in the same legder which it's been created,
12708
+ // We cannot fetch the offer from registry contract event handler since it's getting deleted immediately.
12709
+ await new Promise(async resolve => {
12710
+ while (this.xrplApi.ledgerIndex <= offerLedgerIndex)
12711
+ await new Promise(resolve2 => setTimeout(resolve2, 1000));
12712
+ resolve();
12713
+ });
12714
+
12715
+ await this.xrplAcc.sellNft(offer.index);
12716
+ }
12636
12717
  }
12637
12718
 
12638
12719
  module.exports = {
@@ -12656,7 +12737,9 @@ const RegistryEvents = {
12656
12737
  RegistryInitialized: EvernodeEvents.RegistryInitialized,
12657
12738
  Heartbeat: EvernodeEvents.Heartbeat,
12658
12739
  HostPostDeregistered: EvernodeEvents.HostPostDeregistered,
12659
- DeadHostPrune: EvernodeEvents.DeadHostPrune
12740
+ DeadHostPrune: EvernodeEvents.DeadHostPrune,
12741
+ HostTransfer: EvernodeEvents.HostTransfer,
12742
+ HostRebate: EvernodeEvents.HostRebate
12660
12743
  }
12661
12744
 
12662
12745
  class RegistryClient extends BaseEvernodeClient {
@@ -13391,6 +13474,7 @@ const MemoTypes = {
13391
13474
  HOST_UPDATE_INFO: 'evnHostUpdateReg',
13392
13475
  HEARTBEAT: 'evnHeartbeat',
13393
13476
  HOST_POST_DEREG: 'evnHostPostDereg',
13477
+ HOST_TRANSFER: 'evnTransfer',
13394
13478
  EXTEND_LEASE: 'evnExtendLease',
13395
13479
  EXTEND_SUCCESS: 'evnExtendSuccess',
13396
13480
  EXTEND_ERROR: 'evnExtendError',
@@ -13398,7 +13482,8 @@ const MemoTypes = {
13398
13482
  REGISTRY_INIT: 'evnInitialize',
13399
13483
  REFUND: 'evnRefund',
13400
13484
  REFUND_REF: 'evnRefundRef',
13401
- DEAD_HOST_PRUNE: 'evnDeadHostPrune'
13485
+ DEAD_HOST_PRUNE: 'evnDeadHostPrune',
13486
+ HOST_REBATE: 'evnHostRebate'
13402
13487
  }
13403
13488
 
13404
13489
  const MemoFormats = {
@@ -13450,12 +13535,14 @@ const HookStateKeys = {
13450
13535
  // Prefixes
13451
13536
  PREFIX_HOST_TOKENID: "45565202",
13452
13537
  PREFIX_HOST_ADDR: "45565203",
13538
+ PREFIX_TRANSFEREE_ADDR: "45565204",
13453
13539
  }
13454
13540
 
13455
13541
  const EvernodeEvents = {
13456
13542
  HostRegistered: "HostRegistered",
13457
13543
  HostDeregistered: "HostDeregistered",
13458
13544
  HostPostDeregistered: "HostPostDeregistered",
13545
+ HostTransfer: "HostTransfer",
13459
13546
  AcquireLease: "AcquireLease",
13460
13547
  AcquireSuccess: "AcquireSuccess",
13461
13548
  AcquireError: "AcquireError",
@@ -13466,7 +13553,8 @@ const EvernodeEvents = {
13466
13553
  HostRegUpdated: "HostRegUpdated",
13467
13554
  HostReRegistered: "HostReRegistered",
13468
13555
  RegistryInitialized: "RegistryInitialized",
13469
- DeadHostPrune: "DeadHostPrune"
13556
+ DeadHostPrune: "DeadHostPrune",
13557
+ HostRebate: "HostRebate"
13470
13558
  }
13471
13559
 
13472
13560
  module.exports = {
@@ -13900,6 +13988,7 @@ const HOST_ACT_INS_COUNT_OFFSET = 88;
13900
13988
  const HOST_HEARTBEAT_LEDGER_IDX_OFFSET = 92;
13901
13989
  const HOST_VERSION_OFFSET = 100;
13902
13990
  const HOST_REG_TIMESTAMP_OFFSET = 103;
13991
+ const HOST_TRANSFER_FLAG_OFFSET = 111;
13903
13992
 
13904
13993
  const HOST_ADDRESS_OFFSET = 0;
13905
13994
  const HOST_CPU_MODEL_NAME_OFFSET = 20;
@@ -13922,13 +14011,15 @@ const MOMENT_TYPES = {
13922
14011
  const EVERNODE_PREFIX = 'EVR';
13923
14012
  const HOST_ADDR_KEY_ZERO_COUNT = 8;
13924
14013
  const HOOK_STATE_LEDGER_TYPE_PREFIX = 118; // Decimal value of ASCII 'v'
14014
+ const PENDING_TRANSFER = 1;
13925
14015
 
13926
14016
  class StateHelpers {
13927
14017
  static StateTypes = {
13928
14018
  TOKEN_ID: 'tokenId',
13929
14019
  HOST_ADDR: 'hostAddr',
13930
14020
  SIGLETON: 'singleton',
13931
- CONFIGURATION: 'configuration'
14021
+ CONFIGURATION: 'configuration',
14022
+ TRANSFEREE_ADDR: 'transfereeAddr'
13932
14023
  }
13933
14024
 
13934
14025
  static timeLines = {
@@ -13955,6 +14046,7 @@ class StateHelpers {
13955
14046
  activeInstances: stateDataBuf.readUInt32BE(HOST_ACT_INS_COUNT_OFFSET),
13956
14047
  lastHeartbeatIndex: Number(stateDataBuf.readBigUInt64BE(HOST_HEARTBEAT_LEDGER_IDX_OFFSET)),
13957
14048
  version: `${stateDataBuf.readUInt8(HOST_VERSION_OFFSET)}.${stateDataBuf.readUInt8(HOST_VERSION_OFFSET + 1)}.${stateDataBuf.readUInt8(HOST_VERSION_OFFSET + 2)}`,
14049
+ hasPendingTransfer: (stateDataBuf.readUInt8(HOST_TRANSFER_FLAG_OFFSET) === PENDING_TRANSFER) ? true : false
13958
14050
  }
13959
14051
  if (stateDataBuf.length > HOST_REG_TIMESTAMP_OFFSET)
13960
14052
  data.registrationTimestamp = Number(stateDataBuf.readBigUInt64BE(HOST_REG_TIMESTAMP_OFFSET));
@@ -13994,6 +14086,12 @@ class StateHelpers {
13994
14086
  ...this.decodeTokenIdState(stateData)
13995
14087
  }
13996
14088
  }
14089
+ else if (Buffer.from(HookStateKeys.PREFIX_TRANSFEREE_ADDR, 'hex').compare(stateKey, 0, 4) === 0) {
14090
+ return {
14091
+ type: this.StateTypes.TRANSFEREE_ADDR,
14092
+ key: hexKey
14093
+ }
14094
+ }
13997
14095
  else if (Buffer.from(HookStateKeys.HOST_COUNT, 'hex').compare(stateKey) === 0) {
13998
14096
  return {
13999
14097
  type: this.StateTypes.SIGLETON,
@@ -14482,8 +14580,10 @@ class XrplAccount {
14482
14580
  this.address = address;
14483
14581
 
14484
14582
  this.secret = secret;
14485
- if (this.secret)
14583
+ if (this.secret) {
14486
14584
  this.wallet = xrpl.Wallet.fromSeed(this.secret);
14585
+ this.address= this.wallet.classicAddress;
14586
+ }
14487
14587
 
14488
14588
  this.#txStreamHandler = (eventName, tx, error) => {
14489
14589
  this.#events.emit(eventName, tx, error);
@@ -14579,7 +14679,7 @@ class XrplAccount {
14579
14679
  }
14580
14680
 
14581
14681
  async getAccountTrx(minLedgerIndex = -1, maxLedgerIndex = -1, isForward = true) {
14582
- return await this.xrplApi.getAccountTrx(this.address, { ledger_index_min: minLedgerIndex, ledger_index_max: maxLedgerIndex, forward: isForward});
14682
+ return await this.xrplApi.getAccountTrx(this.address, { ledger_index_min: minLedgerIndex, ledger_index_max: maxLedgerIndex, forward: isForward });
14583
14683
  }
14584
14684
 
14585
14685
  setAccountFields(fields, options = {}) {
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  ],
7
7
  "homepage": "https://github.com/HotPocketDev/evernode-js-client",
8
8
  "license": "MIT",
9
- "version": "0.5.3",
9
+ "version": "0.5.5",
10
10
  "dependencies": {
11
11
  "elliptic": "6.5.4",
12
12
  "ripple-address-codec": "4.2.0",