xrpl 4.4.1 → 4.5.0-smartescrow.1

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 (101) hide show
  1. package/build/xrpl-latest-min.js +1 -1
  2. package/build/xrpl-latest-min.js.map +1 -1
  3. package/build/xrpl-latest.js +12556 -9884
  4. package/build/xrpl-latest.js.map +1 -1
  5. package/dist/npm/Wallet/defaultFaucets.d.ts +2 -1
  6. package/dist/npm/Wallet/defaultFaucets.d.ts.map +1 -1
  7. package/dist/npm/Wallet/defaultFaucets.js +3 -0
  8. package/dist/npm/Wallet/defaultFaucets.js.map +1 -1
  9. package/dist/npm/Wallet/fundWallet.js +1 -1
  10. package/dist/npm/Wallet/fundWallet.js.map +1 -1
  11. package/dist/npm/Wallet/index.d.ts.map +1 -1
  12. package/dist/npm/Wallet/index.js.map +1 -1
  13. package/dist/npm/client/index.d.ts.map +1 -1
  14. package/dist/npm/client/index.js +4 -4
  15. package/dist/npm/client/index.js.map +1 -1
  16. package/dist/npm/client/partialPayment.d.ts.map +1 -1
  17. package/dist/npm/client/partialPayment.js.map +1 -1
  18. package/dist/npm/models/ledger/Escrow.d.ts +2 -0
  19. package/dist/npm/models/ledger/Escrow.d.ts.map +1 -1
  20. package/dist/npm/models/ledger/FeeSettings.d.ts +3 -0
  21. package/dist/npm/models/ledger/FeeSettings.d.ts.map +1 -1
  22. package/dist/npm/models/methods/index.d.ts.map +1 -1
  23. package/dist/npm/models/methods/serverInfo.d.ts +6 -0
  24. package/dist/npm/models/methods/serverInfo.d.ts.map +1 -1
  25. package/dist/npm/models/methods/serverState.d.ts +6 -0
  26. package/dist/npm/models/methods/serverState.d.ts.map +1 -1
  27. package/dist/npm/models/methods/subscribe.d.ts +3 -0
  28. package/dist/npm/models/methods/subscribe.d.ts.map +1 -1
  29. package/dist/npm/models/transactions/MPTokenIssuanceCreate.js +1 -1
  30. package/dist/npm/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
  31. package/dist/npm/models/transactions/MPTokenIssuanceSet.js +2 -2
  32. package/dist/npm/models/transactions/MPTokenIssuanceSet.js.map +1 -1
  33. package/dist/npm/models/transactions/NFTokenCreateOffer.js +1 -1
  34. package/dist/npm/models/transactions/NFTokenCreateOffer.js.map +1 -1
  35. package/dist/npm/models/transactions/batch.d.ts +1 -8
  36. package/dist/npm/models/transactions/batch.d.ts.map +1 -1
  37. package/dist/npm/models/transactions/batch.js +33 -10
  38. package/dist/npm/models/transactions/batch.js.map +1 -1
  39. package/dist/npm/models/transactions/common.d.ts +2 -0
  40. package/dist/npm/models/transactions/common.d.ts.map +1 -1
  41. package/dist/npm/models/transactions/common.js +10 -1
  42. package/dist/npm/models/transactions/common.js.map +1 -1
  43. package/dist/npm/models/transactions/delegateSet.js +2 -2
  44. package/dist/npm/models/transactions/delegateSet.js.map +1 -1
  45. package/dist/npm/models/transactions/escrowCreate.d.ts +2 -0
  46. package/dist/npm/models/transactions/escrowCreate.d.ts.map +1 -1
  47. package/dist/npm/models/transactions/escrowCreate.js +4 -2
  48. package/dist/npm/models/transactions/escrowCreate.js.map +1 -1
  49. package/dist/npm/models/transactions/escrowFinish.d.ts +6 -0
  50. package/dist/npm/models/transactions/escrowFinish.d.ts.map +1 -1
  51. package/dist/npm/models/transactions/escrowFinish.js.map +1 -1
  52. package/dist/npm/models/transactions/metadata.d.ts +2 -1
  53. package/dist/npm/models/transactions/metadata.d.ts.map +1 -1
  54. package/dist/npm/models/transactions/metadata.js.map +1 -1
  55. package/dist/npm/models/transactions/payment.js +1 -1
  56. package/dist/npm/models/transactions/payment.js.map +1 -1
  57. package/dist/npm/models/transactions/setFee.d.ts +3 -0
  58. package/dist/npm/models/transactions/setFee.d.ts.map +1 -1
  59. package/dist/npm/models/utils/flags.js +2 -1
  60. package/dist/npm/models/utils/flags.js.map +1 -1
  61. package/dist/npm/sugar/autofill.d.ts.map +1 -1
  62. package/dist/npm/sugar/autofill.js +69 -65
  63. package/dist/npm/sugar/autofill.js.map +1 -1
  64. package/dist/npm/sugar/getFeeXrp.d.ts.map +1 -1
  65. package/dist/npm/sugar/getFeeXrp.js +2 -4
  66. package/dist/npm/sugar/getFeeXrp.js.map +1 -1
  67. package/dist/npm/sugar/getOrderbook.js +2 -2
  68. package/dist/npm/sugar/getOrderbook.js.map +1 -1
  69. package/dist/npm/utils/getBalanceChanges.js +4 -4
  70. package/dist/npm/utils/getBalanceChanges.js.map +1 -1
  71. package/dist/npm/utils/hashes/SHAMap/LeafNode.d.ts.map +1 -1
  72. package/dist/npm/utils/hashes/SHAMap/LeafNode.js.map +1 -1
  73. package/package.json +4 -4
  74. package/src/Wallet/defaultFaucets.ts +5 -0
  75. package/src/Wallet/fundWallet.ts +1 -1
  76. package/src/Wallet/index.ts +1 -0
  77. package/src/client/index.ts +13 -14
  78. package/src/client/partialPayment.ts +2 -0
  79. package/src/models/ledger/Escrow.ts +4 -1
  80. package/src/models/ledger/FeeSettings.ts +6 -0
  81. package/src/models/methods/index.ts +1 -0
  82. package/src/models/methods/serverInfo.ts +9 -0
  83. package/src/models/methods/serverState.ts +10 -0
  84. package/src/models/methods/subscribe.ts +22 -19
  85. package/src/models/transactions/MPTokenIssuanceCreate.ts +1 -1
  86. package/src/models/transactions/MPTokenIssuanceSet.ts +2 -2
  87. package/src/models/transactions/NFTokenCreateOffer.ts +1 -1
  88. package/src/models/transactions/batch.ts +46 -29
  89. package/src/models/transactions/common.ts +22 -0
  90. package/src/models/transactions/delegateSet.ts +2 -2
  91. package/src/models/transactions/escrowCreate.ts +10 -2
  92. package/src/models/transactions/escrowFinish.ts +9 -0
  93. package/src/models/transactions/metadata.ts +13 -10
  94. package/src/models/transactions/payment.ts +1 -1
  95. package/src/models/transactions/setFee.ts +6 -0
  96. package/src/models/utils/flags.ts +1 -1
  97. package/src/sugar/autofill.ts +59 -43
  98. package/src/sugar/getFeeXrp.ts +2 -4
  99. package/src/sugar/getOrderbook.ts +1 -1
  100. package/src/utils/getBalanceChanges.ts +1 -1
  101. package/src/utils/hashes/SHAMap/LeafNode.ts +1 -0
@@ -158,9 +158,12 @@ export interface LedgerStreamResponse {
158
158
  * If this ledger version includes a SetFee pseudo-transaction the new.
159
159
  * Transaction cost applies starting with the following ledger version.
160
160
  */
161
+ extension_compute?: number
162
+ extension_size?: number
161
163
  fee_base: number
162
164
  /** The reference transaction cost in "fee units". This is not returned after the SetFees amendment is enabled. */
163
165
  fee_ref?: number
166
+ gas_price?: string
164
167
  /** The identifying hash of the ledger version that was closed. */
165
168
  ledger_hash: string
166
169
  /** The ledger index of the ledger that was closed. */
@@ -506,22 +509,22 @@ export type EventTypes =
506
509
  export type OnEventToListenerMap<T extends EventTypes> = T extends 'connected'
507
510
  ? () => void
508
511
  : T extends 'disconnected'
509
- ? (code: number) => void
510
- : T extends 'ledgerClosed'
511
- ? (ledger: LedgerStream) => void
512
- : T extends 'validationReceived'
513
- ? (validation: ValidationStream) => void
514
- : T extends 'transaction'
515
- ? (transaction: TransactionStream) => void
516
- : T extends 'peerStatusChange'
517
- ? (peerStatus: PeerStatusStream) => void
518
- : T extends 'consensusPhase'
519
- ? (consensus: ConsensusStream) => void
520
- : T extends 'manifestReceived'
521
- ? (manifest: ManifestRequest) => void
522
- : T extends 'path_find'
523
- ? (path: PathFindStream) => void
524
- : T extends 'error'
525
- ? // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needs to be any for overload
526
- (...err: any[]) => void
527
- : (...args: never[]) => void
512
+ ? (code: number) => void
513
+ : T extends 'ledgerClosed'
514
+ ? (ledger: LedgerStream) => void
515
+ : T extends 'validationReceived'
516
+ ? (validation: ValidationStream) => void
517
+ : T extends 'transaction'
518
+ ? (transaction: TransactionStream) => void
519
+ : T extends 'peerStatusChange'
520
+ ? (peerStatus: PeerStatusStream) => void
521
+ : T extends 'consensusPhase'
522
+ ? (consensus: ConsensusStream) => void
523
+ : T extends 'manifestReceived'
524
+ ? (manifest: ManifestRequest) => void
525
+ : T extends 'path_find'
526
+ ? (path: PathFindStream) => void
527
+ : T extends 'error'
528
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any -- needs to be any for overload
529
+ (...err: any[]) => void
530
+ : (...args: never[]) => void
@@ -173,7 +173,7 @@ export function validateMPTokenIssuanceCreate(
173
173
  const isTfMPTCanTransfer =
174
174
  typeof flags === 'number'
175
175
  ? isFlagEnabled(flags, MPTokenIssuanceCreateFlags.tfMPTCanTransfer)
176
- : flags.tfMPTCanTransfer ?? false
176
+ : (flags.tfMPTCanTransfer ?? false)
177
177
 
178
178
  if (tx.TransferFee < 0 || tx.TransferFee > MAX_TRANSFER_FEE) {
179
179
  throw new ValidationError(
@@ -73,12 +73,12 @@ export function validateMPTokenIssuanceSet(tx: Record<string, unknown>): void {
73
73
  const isTfMPTLock =
74
74
  typeof flags === 'number'
75
75
  ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTLock)
76
- : flags.tfMPTLock ?? false
76
+ : (flags.tfMPTLock ?? false)
77
77
 
78
78
  const isTfMPTUnlock =
79
79
  typeof flags === 'number'
80
80
  ? isFlagEnabled(flags, MPTokenIssuanceSetFlags.tfMPTUnlock)
81
- : flags.tfMPTUnlock ?? false
81
+ : (flags.tfMPTUnlock ?? false)
82
82
 
83
83
  if (isTfMPTLock && isTfMPTUnlock) {
84
84
  throw new ValidationError('MPTokenIssuanceSet: flag conflict')
@@ -151,7 +151,7 @@ export function validateNFTokenCreateOffer(tx: Record<string, unknown>): void {
151
151
  const isTfSellNFToken =
152
152
  typeof flags === 'number'
153
153
  ? isFlagEnabled(flags, NFTokenCreateOfferFlags.tfSellNFToken)
154
- : flags.tfSellNFToken ?? false
154
+ : (flags.tfSellNFToken ?? false)
155
155
 
156
156
  if (isTfSellNFToken) {
157
157
  validateNFTokenSellOfferCases(tx)
@@ -7,8 +7,10 @@ import {
7
7
  GlobalFlags,
8
8
  GlobalFlagsInterface,
9
9
  isArray,
10
+ isNull,
10
11
  isRecord,
11
12
  isString,
13
+ isValue,
12
14
  validateBaseTransaction,
13
15
  validateOptionalField,
14
16
  validateRequiredField,
@@ -40,18 +42,6 @@ export interface BatchFlagsInterface extends GlobalFlagsInterface {
40
42
  tfIndependent?: boolean
41
43
  }
42
44
 
43
- export type BatchInnerTransaction = SubmittableTransaction & {
44
- Fee?: '0'
45
-
46
- SigningPubKey?: ''
47
-
48
- TxnSignature?: never
49
-
50
- Signers?: never
51
-
52
- LastLedgerSequence?: never
53
- }
54
-
55
45
  export interface BatchSigner {
56
46
  BatchSigner: {
57
47
  Account: string
@@ -73,10 +63,48 @@ export interface Batch extends BaseTransaction {
73
63
  BatchSigners?: BatchSigner[]
74
64
 
75
65
  RawTransactions: Array<{
76
- RawTransaction: BatchInnerTransaction
66
+ RawTransaction: SubmittableTransaction
77
67
  }>
78
68
  }
79
69
 
70
+ function validateBatchInnerTransaction(
71
+ tx: Record<string, unknown>,
72
+ index: number,
73
+ ): void {
74
+ if (tx.TransactionType === 'Batch') {
75
+ throw new ValidationError(
76
+ `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`,
77
+ )
78
+ }
79
+
80
+ // Check for the `tfInnerBatchTxn` flag in the inner transactions
81
+ if (!hasFlag(tx, GlobalFlags.tfInnerBatchTxn, 'tfInnerBatchTxn')) {
82
+ throw new ValidationError(
83
+ `Batch: RawTransactions[${index}] must contain the \`tfInnerBatchTxn\` flag.`,
84
+ )
85
+ }
86
+ validateOptionalField(tx, 'Fee', isValue('0'), {
87
+ paramName: `RawTransactions[${index}].RawTransaction.Fee`,
88
+ txType: 'Batch',
89
+ })
90
+ validateOptionalField(tx, 'SigningPubKey', isValue(''), {
91
+ paramName: `RawTransactions[${index}].RawTransaction.SigningPubKey`,
92
+ txType: 'Batch',
93
+ })
94
+ validateOptionalField(tx, 'TxnSignature', isNull, {
95
+ paramName: `RawTransactions[${index}].RawTransaction.TxnSignature`,
96
+ txType: 'Batch',
97
+ })
98
+ validateOptionalField(tx, 'Signers', isNull, {
99
+ paramName: `RawTransactions[${index}].RawTransaction.Signers`,
100
+ txType: 'Batch',
101
+ })
102
+ validateOptionalField(tx, 'LastLedgerSequence', isNull, {
103
+ paramName: `RawTransactions[${index}].RawTransaction.LastLedgerSequence`,
104
+ txType: 'Batch',
105
+ })
106
+ }
107
+
80
108
  /**
81
109
  * Verify the form and type of a Batch at runtime.
82
110
  *
@@ -101,18 +129,7 @@ export function validateBatch(tx: Record<string, unknown>): void {
101
129
  })
102
130
 
103
131
  const rawTx = rawTxObj.RawTransaction
104
- if (rawTx.TransactionType === 'Batch') {
105
- throw new ValidationError(
106
- `Batch: RawTransactions[${index}] is a Batch transaction. Cannot nest Batch transactions.`,
107
- )
108
- }
109
-
110
- // Check for the `tfInnerBatchTxn` flag in the inner transactions
111
- if (!hasFlag(rawTx, GlobalFlags.tfInnerBatchTxn, 'tfInnerBatchTxn')) {
112
- throw new ValidationError(
113
- `Batch: RawTransactions[${index}] must contain the \`tfInnerBatchTxn\` flag.`,
114
- )
115
- }
132
+ validateBatchInnerTransaction(rawTx, index)
116
133
 
117
134
  // Full validation of each `RawTransaction` object is done in `validate` to avoid dependency cycles
118
135
  })
@@ -132,19 +149,19 @@ export function validateBatch(tx: Record<string, unknown>): void {
132
149
 
133
150
  const signer = signerRecord.BatchSigner
134
151
  validateRequiredField(signer, 'Account', isString, {
135
- paramName: `BatchSigners[${index}].Account`,
152
+ paramName: `BatchSigners[${index}].BatchSigner.Account`,
136
153
  txType: 'Batch',
137
154
  })
138
155
  validateOptionalField(signer, 'SigningPubKey', isString, {
139
- paramName: `BatchSigners[${index}].SigningPubKey`,
156
+ paramName: `BatchSigners[${index}].BatchSigner.SigningPubKey`,
140
157
  txType: 'Batch',
141
158
  })
142
159
  validateOptionalField(signer, 'TxnSignature', isString, {
143
- paramName: `BatchSigners[${index}].TxnSignature`,
160
+ paramName: `BatchSigners[${index}].BatchSigner.TxnSignature`,
144
161
  txType: 'Batch',
145
162
  })
146
163
  validateOptionalField(signer, 'Signers', isArray, {
147
- paramName: `BatchSigners[${index}].Signers`,
164
+ paramName: `BatchSigners[${index}].BatchSigner.Signers`,
148
165
  txType: 'Batch',
149
166
  })
150
167
  })
@@ -152,6 +152,28 @@ export function isNumber(num: unknown): num is number {
152
152
  return typeof num === 'number'
153
153
  }
154
154
 
155
+ /**
156
+ * Verify the form and type of a null value at runtime.
157
+ *
158
+ * @param inp - The value to check the form and type of.
159
+ * @returns Whether the value is properly formed.
160
+ */
161
+ export function isNull(inp: unknown): inp is null {
162
+ return inp == null
163
+ }
164
+
165
+ /**
166
+ * Verify that a certain field has a certain exact value at runtime.
167
+ *
168
+ * @param value The value to compare against.
169
+ * @returns Whether the number is properly formed and within the bounds.
170
+ */
171
+ export function isValue<V>(value: V): (inp: unknown) => inp is V {
172
+ // eslint-disable-next-line func-style -- returning a function
173
+ const isValueInternal = (inp: unknown): inp is V => inp === value
174
+ return isValueInternal
175
+ }
176
+
155
177
  /**
156
178
  * Checks whether the given value is a valid XRPL number string.
157
179
  * Accepts integer, decimal, or scientific notation strings.
@@ -9,7 +9,7 @@ import {
9
9
  } from './common'
10
10
 
11
11
  const PERMISSIONS_MAX_LENGTH = 10
12
- const NON_DELEGATABLE_TRANSACTIONS = new Set([
12
+ const NON_DELEGABLE_TRANSACTIONS = new Set([
13
13
  'AccountSet',
14
14
  'SetRegularKey',
15
15
  'SignerListSet',
@@ -97,7 +97,7 @@ export function validateDelegateSet(tx: Record<string, unknown>): void {
97
97
  if (typeof permissionValue !== 'string') {
98
98
  throw new ValidationError('DelegateSet: PermissionValue must be a string')
99
99
  }
100
- if (NON_DELEGATABLE_TRANSACTIONS.has(permissionValue)) {
100
+ if (NON_DELEGABLE_TRANSACTIONS.has(permissionValue)) {
101
101
  throw new ValidationError(
102
102
  `DelegateSet: PermissionValue contains a non-delegatable transaction ${permissionValue}`,
103
103
  )
@@ -50,6 +50,10 @@ export interface EscrowCreate extends BaseTransaction {
50
50
  * payment, such as a hosted recipient at the destination address.
51
51
  */
52
52
  DestinationTag?: number
53
+
54
+ FinishFunction?: string
55
+
56
+ Data?: string
53
57
  }
54
58
 
55
59
  /**
@@ -71,9 +75,13 @@ export function validateEscrowCreate(tx: Record<string, unknown>): void {
71
75
  )
72
76
  }
73
77
 
74
- if (tx.FinishAfter === undefined && tx.Condition === undefined) {
78
+ if (
79
+ tx.FinishAfter === undefined &&
80
+ tx.Condition === undefined &&
81
+ tx.FinishFunction === undefined
82
+ ) {
75
83
  throw new ValidationError(
76
- 'EscrowCreate: Either Condition or FinishAfter must be specified',
84
+ 'EscrowCreate: Either FinishAfter, Condition, or FinishFunction must be specified',
77
85
  )
78
86
  }
79
87
 
@@ -9,6 +9,7 @@ import {
9
9
  validateRequiredField,
10
10
  MAX_AUTHORIZED_CREDENTIALS,
11
11
  } from './common'
12
+ import type { TransactionMetadataBase } from './metadata'
12
13
 
13
14
  /**
14
15
  * Deliver XRP from a held payment to the recipient.
@@ -38,6 +39,14 @@ export interface EscrowFinish extends BaseTransaction {
38
39
  * The credentials included must not be expired.
39
40
  */
40
41
  CredentialIDs?: string[]
42
+
43
+ ComputationAllowance?: number
44
+ }
45
+
46
+ export interface EscrowFinishMetadata extends TransactionMetadataBase {
47
+ // if ComputationAllowance is present and the Smart Escrow runs
48
+ GasUsed?: number
49
+ WasmReturnCode?: number
41
50
  }
42
51
 
43
52
  /**
@@ -1,6 +1,7 @@
1
1
  import { Amount, MPTAmount } from '../common'
2
2
 
3
3
  import { BaseTransaction } from './common'
4
+ import { EscrowFinish, EscrowFinishMetadata } from './escrowFinish'
4
5
  import {
5
6
  MPTokenIssuanceCreate,
6
7
  MPTokenIssuanceCreateMetadata,
@@ -96,13 +97,15 @@ export type TransactionMetadata<T extends BaseTransaction = Transaction> =
96
97
  T extends Payment
97
98
  ? PaymentMetadata
98
99
  : T extends NFTokenMint
99
- ? NFTokenMintMetadata
100
- : T extends NFTokenCreateOffer
101
- ? NFTokenCreateOfferMetadata
102
- : T extends NFTokenAcceptOffer
103
- ? NFTokenAcceptOfferMetadata
104
- : T extends NFTokenCancelOffer
105
- ? NFTokenCancelOfferMetadata
106
- : T extends MPTokenIssuanceCreate
107
- ? MPTokenIssuanceCreateMetadata
108
- : TransactionMetadataBase
100
+ ? NFTokenMintMetadata
101
+ : T extends NFTokenCreateOffer
102
+ ? NFTokenCreateOfferMetadata
103
+ : T extends NFTokenAcceptOffer
104
+ ? NFTokenAcceptOfferMetadata
105
+ : T extends NFTokenCancelOffer
106
+ ? NFTokenCancelOfferMetadata
107
+ : T extends MPTokenIssuanceCreate
108
+ ? MPTokenIssuanceCreateMetadata
109
+ : T extends EscrowFinish
110
+ ? EscrowFinishMetadata
111
+ : TransactionMetadataBase
@@ -241,7 +241,7 @@ function checkPartialPayment(tx: Record<string, unknown>): void {
241
241
  const isTfPartialPayment =
242
242
  typeof flags === 'number'
243
243
  ? isFlagEnabled(flags, PaymentFlags.tfPartialPayment)
244
- : flags.tfPartialPayment ?? false
244
+ : (flags.tfPartialPayment ?? false)
245
245
 
246
246
  if (!isTfPartialPayment) {
247
247
  throw new ValidationError(
@@ -32,6 +32,12 @@ export interface SetFeePostAmendment extends BaseTransaction {
32
32
  * The incremental reserve, in drops
33
33
  */
34
34
  ReserveIncrementDrops: string
35
+
36
+ ExtensionComputeLimit?: number
37
+
38
+ ExtensionSizeLimit?: number
39
+
40
+ GasPrice?: number
35
41
  }
36
42
 
37
43
  /**
@@ -118,7 +118,7 @@ export function convertTxFlagsToNumber(tx: Transaction): number {
118
118
  }
119
119
 
120
120
  return txFlags[flag]
121
- ? resultFlags | (flagEnum[flag] || GlobalFlags[flag])
121
+ ? resultFlags | (flagEnum[flag] ?? GlobalFlags[flag])
122
122
  : resultFlags
123
123
  }, 0)
124
124
  }
@@ -19,6 +19,11 @@ const LEDGER_OFFSET = 20
19
19
  const RESTRICTED_NETWORKS = 1024
20
20
  const REQUIRED_NETWORKID_VERSION = '1.11.0'
21
21
 
22
+ const MICRO_DROPS_PER_DROP = 1_000_000
23
+
24
+ const WASM_FIXED_UPLOAD_COST = 100
25
+ const WASM_DROPS_PER_BYTE = 5
26
+
22
27
  /**
23
28
  * Determines whether the source rippled version is not later than the target rippled version.
24
29
  * Example usage: isNotLaterRippledVersion('1.10.0', '1.11.0') returns true.
@@ -258,6 +263,17 @@ async function fetchOwnerReserveFee(client: Client): Promise<BigNumber> {
258
263
  return new BigNumber(fee)
259
264
  }
260
265
 
266
+ async function fetchGasPrice(client: Client): Promise<BigNumber> {
267
+ const response = await client.request({ command: 'server_state' })
268
+ const gasPrice = response.result.state.validated_ledger?.gas_price
269
+
270
+ if (gasPrice == null) {
271
+ return Promise.reject(new Error('Could not fetch Owner Reserve.'))
272
+ }
273
+
274
+ return new BigNumber(gasPrice)
275
+ }
276
+
261
277
  /**
262
278
  * Calculates the fee per transaction type.
263
279
  *
@@ -266,40 +282,57 @@ async function fetchOwnerReserveFee(client: Client): Promise<BigNumber> {
266
282
  * @param [signersCount=0] - The number of signers (default is 0). Only used for multisigning.
267
283
  * @returns A promise that returns the fee.
268
284
  */
269
-
285
+ // eslint-disable-next-line max-lines-per-function, complexity -- necessary to check for many transaction types.
270
286
  async function calculateFeePerTransactionType(
271
287
  client: Client,
272
288
  tx: Transaction,
273
289
  signersCount = 0,
274
290
  ): Promise<BigNumber> {
275
291
  const netFeeXRP = await getFeeXrp(client)
276
- const netFeeDrops = xrpToDrops(netFeeXRP)
277
- let baseFee = new BigNumber(netFeeDrops)
292
+ const netFeeDrops = new BigNumber(xrpToDrops(netFeeXRP))
293
+ let baseFee = netFeeDrops
278
294
 
279
295
  const isSpecialTxCost = ['AccountDelete', 'AMMCreate'].includes(
280
296
  tx.TransactionType,
281
297
  )
282
298
 
283
- // EscrowFinish Transaction with Fulfillment
284
- if (tx.TransactionType === 'EscrowFinish' && tx.Fulfillment != null) {
285
- const fulfillmentBytesSize: number = Math.ceil(tx.Fulfillment.length / 2)
286
- // BaseFee × (33 + (Fulfillment size in bytes / 16))
287
- baseFee = new BigNumber(
288
- // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- expected use of magic numbers
289
- scaleValue(netFeeDrops, 33 + fulfillmentBytesSize / 16),
299
+ // EscrowCreate transaction with FinishFunction
300
+ if (tx.TransactionType === 'EscrowCreate' && tx.FinishFunction != null) {
301
+ baseFee = baseFee
302
+ .plus(WASM_FIXED_UPLOAD_COST)
303
+ .plus((WASM_DROPS_PER_BYTE * tx.FinishFunction.length) / 2)
304
+ } else if (tx.TransactionType === 'EscrowFinish') {
305
+ // EscrowFinish Transaction with Fulfillment/ComputationAllowance
306
+ if (tx.Fulfillment != null) {
307
+ const fulfillmentBytesSize: number = Math.ceil(tx.Fulfillment.length / 2)
308
+ // BaseFee × (33 + (Fulfillment size in bytes / 16))
309
+ baseFee = netFeeDrops.multipliedBy(
310
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- expected use of magic numbers
311
+ 33 + fulfillmentBytesSize / 16,
312
+ )
313
+ }
314
+ if (tx.ComputationAllowance != null) {
315
+ const gasPrice = await fetchGasPrice(client)
316
+ const extraFee: BigNumber = gasPrice
317
+ .multipliedBy(tx.ComputationAllowance)
318
+ .dividedBy(MICRO_DROPS_PER_DROP)
319
+ baseFee = baseFee.plus(extraFee)
320
+ }
321
+ } else if (tx.TransactionType === 'Batch') {
322
+ const rawTxFees = await tx.RawTransactions.reduce(
323
+ async (acc, rawTxn) => {
324
+ const resolvedAcc = await acc
325
+ const fee = await calculateFeePerTransactionType(
326
+ client,
327
+ rawTxn.RawTransaction,
328
+ )
329
+ return BigNumber.sum(resolvedAcc, fee)
330
+ },
331
+ Promise.resolve(new BigNumber(0)),
290
332
  )
333
+ baseFee = BigNumber.sum(baseFee.times(2), rawTxFees)
291
334
  } else if (isSpecialTxCost) {
292
335
  baseFee = await fetchOwnerReserveFee(client)
293
- } else if (tx.TransactionType === 'Batch') {
294
- const rawTxFees = await tx.RawTransactions.reduce(async (acc, rawTxn) => {
295
- const resolvedAcc = await acc
296
- const fee = await calculateFeePerTransactionType(
297
- client,
298
- rawTxn.RawTransaction,
299
- )
300
- return BigNumber.sum(resolvedAcc, fee)
301
- }, Promise.resolve(new BigNumber(0)))
302
- baseFee = BigNumber.sum(baseFee.times(2), rawTxFees)
303
336
  }
304
337
 
305
338
  /*
@@ -307,7 +340,7 @@ async function calculateFeePerTransactionType(
307
340
  * BaseFee × (1 + Number of Signatures Provided)
308
341
  */
309
342
  if (signersCount > 0) {
310
- baseFee = BigNumber.sum(baseFee, scaleValue(netFeeDrops, signersCount))
343
+ baseFee = BigNumber.sum(baseFee, netFeeDrops.multipliedBy(signersCount))
311
344
  }
312
345
 
313
346
  const maxFeeDrops = xrpToDrops(client.maxFeeXRP)
@@ -337,17 +370,6 @@ export async function getTransactionFee(
337
370
  tx.Fee = fee.toString(10)
338
371
  }
339
372
 
340
- /**
341
- * Scales the given value by multiplying it with the provided multiplier.
342
- *
343
- * @param value - The value to be scaled.
344
- * @param multiplier - The multiplier to scale the value.
345
- * @returns The scaled value as a string.
346
- */
347
- function scaleValue(value, multiplier): string {
348
- return new BigNumber(value).times(multiplier).toString()
349
- }
350
-
351
373
  /**
352
374
  * Sets the latest validated ledger sequence for the transaction.
353
375
  *
@@ -403,12 +425,9 @@ export async function checkAccountDeleteBlockers(
403
425
  */
404
426
  export function handleDeliverMax(tx: Payment): void {
405
427
  if (tx.DeliverMax != null) {
406
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here
407
- if (tx.Amount == null) {
408
- // If only DeliverMax is provided, use it to populate the Amount field
409
- // eslint-disable-next-line no-param-reassign -- known RPC-level property
410
- tx.Amount = tx.DeliverMax
411
- }
428
+ // If only DeliverMax is provided, use it to populate the Amount field
429
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, no-param-reassign -- needed here
430
+ tx.Amount ??= tx.DeliverMax
412
431
 
413
432
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed here
414
433
  if (tx.Amount != null && tx.Amount !== tx.DeliverMax) {
@@ -436,7 +455,7 @@ export async function autofillBatchTxn(
436
455
  ): Promise<void> {
437
456
  const accountSequences: Record<string, number> = {}
438
457
 
439
- for await (const rawTxn of tx.RawTransactions) {
458
+ for (const rawTxn of tx.RawTransactions) {
440
459
  const txn = rawTxn.RawTransaction
441
460
 
442
461
  // Sequence processing
@@ -445,6 +464,7 @@ export async function autofillBatchTxn(
445
464
  txn.Sequence = accountSequences[txn.Account]
446
465
  accountSequences[txn.Account] += 1
447
466
  } else {
467
+ // eslint-disable-next-line no-await-in-loop -- It has to wait
448
468
  const nextSequence = await getNextValidSequenceNumber(
449
469
  client,
450
470
  txn.Account,
@@ -458,28 +478,24 @@ export async function autofillBatchTxn(
458
478
 
459
479
  if (txn.Fee == null) {
460
480
  txn.Fee = '0'
461
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS checks
462
481
  } else if (txn.Fee !== '0') {
463
482
  throw new XrplError('Must have `Fee of "0" in inner Batch transaction.')
464
483
  }
465
484
 
466
485
  if (txn.SigningPubKey == null) {
467
486
  txn.SigningPubKey = ''
468
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS checks
469
487
  } else if (txn.SigningPubKey !== '') {
470
488
  throw new XrplError(
471
489
  'Must have `SigningPubKey` of "" in inner Batch transaction.',
472
490
  )
473
491
  }
474
492
 
475
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS checks
476
493
  if (txn.TxnSignature != null) {
477
494
  throw new XrplError(
478
495
  'Must not have `TxnSignature` in inner Batch transaction.',
479
496
  )
480
497
  }
481
498
 
482
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- needed for JS checks
483
499
  if (txn.Signers != null) {
484
500
  throw new XrplError('Must not have `Signers` in inner Batch transaction.')
485
501
  }
@@ -35,10 +35,8 @@ export default async function getFeeXrp(
35
35
  }
36
36
 
37
37
  const baseFeeXrp = new BigNumber(baseFee)
38
- if (serverInfo.load_factor == null) {
39
- // https://github.com/ripple/rippled/issues/3812#issuecomment-816871100
40
- serverInfo.load_factor = 1
41
- }
38
+ // https://github.com/ripple/rippled/issues/3812#issuecomment-816871100
39
+ serverInfo.load_factor ??= 1
42
40
  let fee = baseFeeXrp.times(serverInfo.load_factor).times(feeCushion)
43
41
 
44
42
  // Cap fee to `client.maxFeeXRP`
@@ -127,7 +127,7 @@ export function createBookOffersRequest(
127
127
  ledger_index: options.ledger_index ?? 'validated',
128
128
  ledger_hash: options.ledger_hash === null ? undefined : options.ledger_hash,
129
129
  limit: options.limit ?? DEFAULT_LIMIT,
130
- taker: options.taker ? options.taker : undefined,
130
+ taker: options.taker ?? undefined,
131
131
  }
132
132
 
133
133
  return request
@@ -134,7 +134,7 @@ function getTrustlineQuantity(node: NormalizedNode): BalanceChange[] | null {
134
134
  * If an offer is placed to acquire an asset with no existing trustline,
135
135
  * the trustline can be created when the offer is taken.
136
136
  */
137
- const fields = node.NewFields == null ? node.FinalFields : node.NewFields
137
+ const fields = node.NewFields ?? node.FinalFields
138
138
 
139
139
  // the balance is always from low node's perspective
140
140
  const result = {
@@ -35,6 +35,7 @@ class LeafNode extends Node {
35
35
  * @throws If node is of unknown type.
36
36
  */
37
37
  public get hash(): string {
38
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- TODO: https://github.com/XRPLF/xrpl.js/issues/3060
38
39
  switch (this.type) {
39
40
  case NodeType.ACCOUNT_STATE: {
40
41
  const leafPrefix = HashPrefix.LEAF_NODE.toString(HEX)