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.
- package/build/xrpl-latest-min.js +1 -1
- package/build/xrpl-latest-min.js.map +1 -1
- package/build/xrpl-latest.js +12556 -9884
- package/build/xrpl-latest.js.map +1 -1
- package/dist/npm/Wallet/defaultFaucets.d.ts +2 -1
- package/dist/npm/Wallet/defaultFaucets.d.ts.map +1 -1
- package/dist/npm/Wallet/defaultFaucets.js +3 -0
- package/dist/npm/Wallet/defaultFaucets.js.map +1 -1
- package/dist/npm/Wallet/fundWallet.js +1 -1
- package/dist/npm/Wallet/fundWallet.js.map +1 -1
- package/dist/npm/Wallet/index.d.ts.map +1 -1
- package/dist/npm/Wallet/index.js.map +1 -1
- package/dist/npm/client/index.d.ts.map +1 -1
- package/dist/npm/client/index.js +4 -4
- package/dist/npm/client/index.js.map +1 -1
- package/dist/npm/client/partialPayment.d.ts.map +1 -1
- package/dist/npm/client/partialPayment.js.map +1 -1
- package/dist/npm/models/ledger/Escrow.d.ts +2 -0
- package/dist/npm/models/ledger/Escrow.d.ts.map +1 -1
- package/dist/npm/models/ledger/FeeSettings.d.ts +3 -0
- package/dist/npm/models/ledger/FeeSettings.d.ts.map +1 -1
- package/dist/npm/models/methods/index.d.ts.map +1 -1
- package/dist/npm/models/methods/serverInfo.d.ts +6 -0
- package/dist/npm/models/methods/serverInfo.d.ts.map +1 -1
- package/dist/npm/models/methods/serverState.d.ts +6 -0
- package/dist/npm/models/methods/serverState.d.ts.map +1 -1
- package/dist/npm/models/methods/subscribe.d.ts +3 -0
- package/dist/npm/models/methods/subscribe.d.ts.map +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.js +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceSet.js +2 -2
- package/dist/npm/models/transactions/MPTokenIssuanceSet.js.map +1 -1
- package/dist/npm/models/transactions/NFTokenCreateOffer.js +1 -1
- package/dist/npm/models/transactions/NFTokenCreateOffer.js.map +1 -1
- package/dist/npm/models/transactions/batch.d.ts +1 -8
- package/dist/npm/models/transactions/batch.d.ts.map +1 -1
- package/dist/npm/models/transactions/batch.js +33 -10
- package/dist/npm/models/transactions/batch.js.map +1 -1
- package/dist/npm/models/transactions/common.d.ts +2 -0
- package/dist/npm/models/transactions/common.d.ts.map +1 -1
- package/dist/npm/models/transactions/common.js +10 -1
- package/dist/npm/models/transactions/common.js.map +1 -1
- package/dist/npm/models/transactions/delegateSet.js +2 -2
- package/dist/npm/models/transactions/delegateSet.js.map +1 -1
- package/dist/npm/models/transactions/escrowCreate.d.ts +2 -0
- package/dist/npm/models/transactions/escrowCreate.d.ts.map +1 -1
- package/dist/npm/models/transactions/escrowCreate.js +4 -2
- package/dist/npm/models/transactions/escrowCreate.js.map +1 -1
- package/dist/npm/models/transactions/escrowFinish.d.ts +6 -0
- package/dist/npm/models/transactions/escrowFinish.d.ts.map +1 -1
- package/dist/npm/models/transactions/escrowFinish.js.map +1 -1
- package/dist/npm/models/transactions/metadata.d.ts +2 -1
- package/dist/npm/models/transactions/metadata.d.ts.map +1 -1
- package/dist/npm/models/transactions/metadata.js.map +1 -1
- package/dist/npm/models/transactions/payment.js +1 -1
- package/dist/npm/models/transactions/payment.js.map +1 -1
- package/dist/npm/models/transactions/setFee.d.ts +3 -0
- package/dist/npm/models/transactions/setFee.d.ts.map +1 -1
- package/dist/npm/models/utils/flags.js +2 -1
- package/dist/npm/models/utils/flags.js.map +1 -1
- package/dist/npm/sugar/autofill.d.ts.map +1 -1
- package/dist/npm/sugar/autofill.js +69 -65
- package/dist/npm/sugar/autofill.js.map +1 -1
- package/dist/npm/sugar/getFeeXrp.d.ts.map +1 -1
- package/dist/npm/sugar/getFeeXrp.js +2 -4
- package/dist/npm/sugar/getFeeXrp.js.map +1 -1
- package/dist/npm/sugar/getOrderbook.js +2 -2
- package/dist/npm/sugar/getOrderbook.js.map +1 -1
- package/dist/npm/utils/getBalanceChanges.js +4 -4
- package/dist/npm/utils/getBalanceChanges.js.map +1 -1
- package/dist/npm/utils/hashes/SHAMap/LeafNode.d.ts.map +1 -1
- package/dist/npm/utils/hashes/SHAMap/LeafNode.js.map +1 -1
- package/package.json +4 -4
- package/src/Wallet/defaultFaucets.ts +5 -0
- package/src/Wallet/fundWallet.ts +1 -1
- package/src/Wallet/index.ts +1 -0
- package/src/client/index.ts +13 -14
- package/src/client/partialPayment.ts +2 -0
- package/src/models/ledger/Escrow.ts +4 -1
- package/src/models/ledger/FeeSettings.ts +6 -0
- package/src/models/methods/index.ts +1 -0
- package/src/models/methods/serverInfo.ts +9 -0
- package/src/models/methods/serverState.ts +10 -0
- package/src/models/methods/subscribe.ts +22 -19
- package/src/models/transactions/MPTokenIssuanceCreate.ts +1 -1
- package/src/models/transactions/MPTokenIssuanceSet.ts +2 -2
- package/src/models/transactions/NFTokenCreateOffer.ts +1 -1
- package/src/models/transactions/batch.ts +46 -29
- package/src/models/transactions/common.ts +22 -0
- package/src/models/transactions/delegateSet.ts +2 -2
- package/src/models/transactions/escrowCreate.ts +10 -2
- package/src/models/transactions/escrowFinish.ts +9 -0
- package/src/models/transactions/metadata.ts +13 -10
- package/src/models/transactions/payment.ts +1 -1
- package/src/models/transactions/setFee.ts +6 -0
- package/src/models/utils/flags.ts +1 -1
- package/src/sugar/autofill.ts +59 -43
- package/src/sugar/getFeeXrp.ts +2 -4
- package/src/sugar/getOrderbook.ts +1 -1
- package/src/utils/getBalanceChanges.ts +1 -1
- 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
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
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:
|
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
|
-
|
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
|
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 (
|
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 (
|
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
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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(
|
package/src/sugar/autofill.ts
CHANGED
@@ -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 =
|
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
|
-
//
|
284
|
-
if (tx.TransactionType === '
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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,
|
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
|
-
//
|
407
|
-
|
408
|
-
|
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
|
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
|
}
|
package/src/sugar/getFeeXrp.ts
CHANGED
@@ -35,10 +35,8 @@ export default async function getFeeXrp(
|
|
35
35
|
}
|
36
36
|
|
37
37
|
const baseFeeXrp = new BigNumber(baseFee)
|
38
|
-
|
39
|
-
|
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
|
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
|
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)
|