xrpl 4.4.0-smartescrow.0 → 4.5.0-smartescrow.0
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 +191 -26
- package/build/xrpl-latest.js.map +1 -1
- package/dist/npm/models/common/index.d.ts +16 -0
- package/dist/npm/models/common/index.d.ts.map +1 -1
- package/dist/npm/models/ledger/AccountRoot.d.ts +3 -1
- package/dist/npm/models/ledger/AccountRoot.d.ts.map +1 -1
- package/dist/npm/models/ledger/AccountRoot.js +1 -0
- package/dist/npm/models/ledger/AccountRoot.js.map +1 -1
- package/dist/npm/models/ledger/DirectoryNode.d.ts +1 -0
- package/dist/npm/models/ledger/DirectoryNode.d.ts.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/MPToken.d.ts +1 -0
- package/dist/npm/models/ledger/MPToken.d.ts.map +1 -1
- package/dist/npm/models/ledger/MPTokenIssuance.d.ts +1 -0
- package/dist/npm/models/ledger/MPTokenIssuance.d.ts.map +1 -1
- package/dist/npm/models/ledger/Offer.d.ts +10 -1
- package/dist/npm/models/ledger/Offer.d.ts.map +1 -1
- package/dist/npm/models/ledger/Offer.js +1 -0
- package/dist/npm/models/ledger/Offer.js.map +1 -1
- package/dist/npm/models/methods/bookOffers.d.ts +1 -0
- package/dist/npm/models/methods/bookOffers.d.ts.map +1 -1
- package/dist/npm/models/methods/pathFind.d.ts +2 -0
- package/dist/npm/models/methods/pathFind.d.ts.map +1 -1
- package/dist/npm/models/methods/ripplePathFind.d.ts +1 -0
- package/dist/npm/models/methods/ripplePathFind.d.ts.map +1 -1
- package/dist/npm/models/methods/subscribe.d.ts +4 -0
- package/dist/npm/models/methods/subscribe.d.ts.map +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.d.ts +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.d.ts.map +1 -1
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.js +14 -5
- package/dist/npm/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
- package/dist/npm/models/transactions/accountSet.d.ts +2 -1
- package/dist/npm/models/transactions/accountSet.d.ts.map +1 -1
- package/dist/npm/models/transactions/accountSet.js +1 -0
- package/dist/npm/models/transactions/accountSet.js.map +1 -1
- package/dist/npm/models/transactions/common.d.ts +4 -0
- package/dist/npm/models/transactions/common.d.ts.map +1 -1
- package/dist/npm/models/transactions/common.js +134 -1
- package/dist/npm/models/transactions/common.js.map +1 -1
- package/dist/npm/models/transactions/escrowCreate.d.ts +2 -1
- package/dist/npm/models/transactions/escrowCreate.d.ts.map +1 -1
- package/dist/npm/models/transactions/escrowCreate.js +1 -6
- package/dist/npm/models/transactions/escrowCreate.js.map +1 -1
- package/dist/npm/models/transactions/escrowFinish.d.ts +5 -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/index.d.ts +1 -1
- package/dist/npm/models/transactions/index.d.ts.map +1 -1
- package/dist/npm/models/transactions/index.js +2 -1
- package/dist/npm/models/transactions/index.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/offerCreate.d.ts +4 -1
- package/dist/npm/models/transactions/offerCreate.d.ts.map +1 -1
- package/dist/npm/models/transactions/offerCreate.js +10 -0
- package/dist/npm/models/transactions/offerCreate.js.map +1 -1
- package/dist/npm/models/transactions/payment.d.ts +1 -0
- package/dist/npm/models/transactions/payment.d.ts.map +1 -1
- package/dist/npm/models/transactions/payment.js +4 -3
- package/dist/npm/models/transactions/payment.js.map +1 -1
- package/dist/npm/models/transactions/vaultCreate.d.ts.map +1 -1
- package/dist/npm/models/transactions/vaultCreate.js +13 -4
- package/dist/npm/models/transactions/vaultCreate.js.map +1 -1
- package/dist/npm/models/transactions/vaultDeposit.d.ts +2 -2
- package/dist/npm/models/transactions/vaultDeposit.d.ts.map +1 -1
- package/dist/npm/models/transactions/vaultDeposit.js.map +1 -1
- package/dist/npm/models/transactions/vaultWithdraw.d.ts +2 -2
- package/dist/npm/models/transactions/vaultWithdraw.d.ts.map +1 -1
- package/dist/npm/models/transactions/vaultWithdraw.js.map +1 -1
- package/dist/npm/snippets/src/permissionedDEX.d.ts +2 -0
- package/dist/npm/snippets/src/permissionedDEX.d.ts.map +1 -0
- package/dist/npm/snippets/src/permissionedDEX.js +173 -0
- package/dist/npm/snippets/src/permissionedDEX.js.map +1 -0
- package/dist/npm/snippets/tsconfig.tsbuildinfo +1 -1
- package/dist/npm/src/models/common/index.d.ts +16 -0
- package/dist/npm/src/models/common/index.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/AccountRoot.d.ts +3 -1
- package/dist/npm/src/models/ledger/AccountRoot.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/AccountRoot.js +1 -0
- package/dist/npm/src/models/ledger/AccountRoot.js.map +1 -1
- package/dist/npm/src/models/ledger/DirectoryNode.d.ts +1 -0
- package/dist/npm/src/models/ledger/DirectoryNode.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/Escrow.d.ts +2 -0
- package/dist/npm/src/models/ledger/Escrow.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/MPToken.d.ts +1 -0
- package/dist/npm/src/models/ledger/MPToken.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/MPTokenIssuance.d.ts +1 -0
- package/dist/npm/src/models/ledger/MPTokenIssuance.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/Offer.d.ts +10 -1
- package/dist/npm/src/models/ledger/Offer.d.ts.map +1 -1
- package/dist/npm/src/models/ledger/Offer.js +1 -0
- package/dist/npm/src/models/ledger/Offer.js.map +1 -1
- package/dist/npm/src/models/methods/bookOffers.d.ts +1 -0
- package/dist/npm/src/models/methods/bookOffers.d.ts.map +1 -1
- package/dist/npm/src/models/methods/pathFind.d.ts +2 -0
- package/dist/npm/src/models/methods/pathFind.d.ts.map +1 -1
- package/dist/npm/src/models/methods/ripplePathFind.d.ts +1 -0
- package/dist/npm/src/models/methods/ripplePathFind.d.ts.map +1 -1
- package/dist/npm/src/models/methods/subscribe.d.ts +4 -0
- package/dist/npm/src/models/methods/subscribe.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.d.ts +1 -1
- package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.js +14 -5
- package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
- package/dist/npm/src/models/transactions/accountSet.d.ts +2 -1
- package/dist/npm/src/models/transactions/accountSet.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/accountSet.js +1 -0
- package/dist/npm/src/models/transactions/accountSet.js.map +1 -1
- package/dist/npm/src/models/transactions/common.d.ts +4 -0
- package/dist/npm/src/models/transactions/common.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/common.js +134 -1
- package/dist/npm/src/models/transactions/common.js.map +1 -1
- package/dist/npm/src/models/transactions/escrowCreate.d.ts +2 -1
- package/dist/npm/src/models/transactions/escrowCreate.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/escrowCreate.js +1 -6
- package/dist/npm/src/models/transactions/escrowCreate.js.map +1 -1
- package/dist/npm/src/models/transactions/escrowFinish.d.ts +5 -0
- package/dist/npm/src/models/transactions/escrowFinish.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/escrowFinish.js.map +1 -1
- package/dist/npm/src/models/transactions/index.d.ts +1 -1
- package/dist/npm/src/models/transactions/index.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/index.js +2 -1
- package/dist/npm/src/models/transactions/index.js.map +1 -1
- package/dist/npm/src/models/transactions/metadata.d.ts +2 -1
- package/dist/npm/src/models/transactions/metadata.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/metadata.js.map +1 -1
- package/dist/npm/src/models/transactions/offerCreate.d.ts +4 -1
- package/dist/npm/src/models/transactions/offerCreate.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/offerCreate.js +10 -0
- package/dist/npm/src/models/transactions/offerCreate.js.map +1 -1
- package/dist/npm/src/models/transactions/payment.d.ts +1 -0
- package/dist/npm/src/models/transactions/payment.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/payment.js +4 -3
- package/dist/npm/src/models/transactions/payment.js.map +1 -1
- package/dist/npm/src/models/transactions/vaultCreate.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/vaultCreate.js +13 -4
- package/dist/npm/src/models/transactions/vaultCreate.js.map +1 -1
- package/dist/npm/src/models/transactions/vaultDeposit.d.ts +2 -2
- package/dist/npm/src/models/transactions/vaultDeposit.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/vaultDeposit.js.map +1 -1
- package/dist/npm/src/models/transactions/vaultWithdraw.d.ts +2 -2
- package/dist/npm/src/models/transactions/vaultWithdraw.d.ts.map +1 -1
- package/dist/npm/src/models/transactions/vaultWithdraw.js.map +1 -1
- package/package.json +4 -4
- package/src/models/common/index.ts +25 -0
- package/src/models/ledger/AccountRoot.ts +10 -0
- package/src/models/ledger/DirectoryNode.ts +3 -0
- package/src/models/ledger/Escrow.ts +13 -1
- package/src/models/ledger/MPToken.ts +1 -0
- package/src/models/ledger/MPTokenIssuance.ts +1 -0
- package/src/models/ledger/Offer.ts +21 -0
- package/src/models/methods/bookOffers.ts +7 -0
- package/src/models/methods/pathFind.ts +10 -0
- package/src/models/methods/ripplePathFind.ts +5 -0
- package/src/models/methods/subscribe.ts +21 -0
- package/src/models/transactions/MPTokenIssuanceCreate.ts +33 -10
- package/src/models/transactions/accountSet.ts +2 -0
- package/src/models/transactions/common.ts +236 -1
- package/src/models/transactions/escrowCreate.ts +8 -12
- package/src/models/transactions/escrowFinish.ts +7 -0
- package/src/models/transactions/index.ts +1 -1
- package/src/models/transactions/metadata.ts +3 -0
- package/src/models/transactions/offerCreate.ts +25 -0
- package/src/models/transactions/payment.ts +18 -6
- package/src/models/transactions/vaultCreate.ts +30 -6
- package/src/models/transactions/vaultDeposit.ts +3 -2
- package/src/models/transactions/vaultWithdraw.ts +3 -2
@@ -2,6 +2,19 @@ import { Amount } from '../common'
|
|
2
2
|
|
3
3
|
import { BaseLedgerEntry, HasPreviousTxnID } from './BaseLedgerEntry'
|
4
4
|
|
5
|
+
export interface Book {
|
6
|
+
Book: {
|
7
|
+
/** The ID of the offer directory that links to this offer. */
|
8
|
+
BookDirectory: string
|
9
|
+
|
10
|
+
/**
|
11
|
+
* A hint indicating which page of the offer directory links to this entry,
|
12
|
+
* in case the directory consists of multiple pages.
|
13
|
+
*/
|
14
|
+
BookNode: string
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
5
18
|
export default interface Offer extends BaseLedgerEntry, HasPreviousTxnID {
|
6
19
|
LedgerEntryType: 'Offer'
|
7
20
|
/** A bit-map of boolean flags enabled for this Offer. */
|
@@ -34,9 +47,17 @@ export default interface Offer extends BaseLedgerEntry, HasPreviousTxnID {
|
|
34
47
|
OwnerNode: string
|
35
48
|
/** The time this Offer expires, in seconds since the Ripple Epoch. */
|
36
49
|
Expiration?: number
|
50
|
+
/** The domain that the offer must be a part of. */
|
51
|
+
DomainID?: string
|
52
|
+
/**
|
53
|
+
* An additional list of order book directories that this offer belongs to.
|
54
|
+
* Currently this field only applicable to hybrid offers.
|
55
|
+
*/
|
56
|
+
AdditionalBooks?: Book[]
|
37
57
|
}
|
38
58
|
|
39
59
|
export enum OfferFlags {
|
40
60
|
lsfPassive = 0x00010000,
|
41
61
|
lsfSell = 0x00020000,
|
62
|
+
lsfHybrid = 0x00040000,
|
42
63
|
}
|
@@ -39,6 +39,13 @@ export interface BookOffersRequest extends BaseRequest, LookupByLedgerRequest {
|
|
39
39
|
* currency amounts.
|
40
40
|
*/
|
41
41
|
taker_pays: BookOfferCurrency
|
42
|
+
/**
|
43
|
+
* The object ID of a PermissionedDomain object. If this field is provided,
|
44
|
+
* the response will include only valid domain offers associated with that
|
45
|
+
* specific domain. If omitted, the response will include only hybrid and open
|
46
|
+
* offers for the trading pair, excluding all domain-specific offers.
|
47
|
+
*/
|
48
|
+
domain?: string
|
42
49
|
}
|
43
50
|
|
44
51
|
export interface BookOffer extends Offer {
|
@@ -30,6 +30,11 @@ export interface PathFindCreateRequest extends BasePathFindRequest {
|
|
30
30
|
* about, or to check the overall cost to make a payment along a certain path.
|
31
31
|
*/
|
32
32
|
paths?: Path[]
|
33
|
+
/**
|
34
|
+
* The object ID of a PermissionedDomain object. If this field is included,
|
35
|
+
* then only valid paths for this domain will be returned.
|
36
|
+
*/
|
37
|
+
domain?: string
|
33
38
|
}
|
34
39
|
|
35
40
|
/** Stop sending pathfinding information. */
|
@@ -97,6 +102,11 @@ export interface PathFindResponse extends BaseResponse {
|
|
97
102
|
* Continues to send updates each time a new ledger closes.
|
98
103
|
*/
|
99
104
|
full_reply: boolean
|
105
|
+
/**
|
106
|
+
* The object ID of a PermissionedDomain object, if the orderbook shown is
|
107
|
+
* for a specific domain.
|
108
|
+
*/
|
109
|
+
domain?: string
|
100
110
|
/**
|
101
111
|
* The ID provided in the WebSocket request is included again at this
|
102
112
|
* level.
|
@@ -38,6 +38,11 @@ export interface RipplePathFindRequest
|
|
38
38
|
* and optional issuer field, like how currency amounts are specified.
|
39
39
|
*/
|
40
40
|
source_currencies?: SourceCurrencyAmount[]
|
41
|
+
/**
|
42
|
+
* The object ID of a PermissionedDomain object. If this field is included,
|
43
|
+
* then only valid paths for this domain will be returned.
|
44
|
+
*/
|
45
|
+
domain?: string
|
41
46
|
}
|
42
47
|
|
43
48
|
export interface RipplePathFindPathOption {
|
@@ -39,6 +39,12 @@ export interface SubscribeBook {
|
|
39
39
|
snapshot?: boolean
|
40
40
|
/** If true, return both sides of the order book. The default is false. */
|
41
41
|
both?: boolean
|
42
|
+
/**
|
43
|
+
* The object ID of a PermissionedDomain object. If this field is included,
|
44
|
+
* then the offers will be filtered to only show the valid domain offers for
|
45
|
+
* that domain.
|
46
|
+
*/
|
47
|
+
domain?: string
|
42
48
|
}
|
43
49
|
|
44
50
|
/**
|
@@ -136,6 +142,11 @@ export interface LedgerStream extends BaseStream {
|
|
136
142
|
* connected but has not yet obtained a ledger from the network.
|
137
143
|
*/
|
138
144
|
validated_ledgers?: string
|
145
|
+
|
146
|
+
/**
|
147
|
+
* The network from which the ledger stream is received.
|
148
|
+
*/
|
149
|
+
network_id?: number
|
139
150
|
}
|
140
151
|
|
141
152
|
/**
|
@@ -175,6 +186,11 @@ export interface LedgerStreamResponse {
|
|
175
186
|
* connected but has not yet obtained a ledger from the network.
|
176
187
|
*/
|
177
188
|
validated_ledgers?: string
|
189
|
+
|
190
|
+
/**
|
191
|
+
* The network from which the ledger stream is received.
|
192
|
+
*/
|
193
|
+
network_id?: number
|
178
194
|
}
|
179
195
|
|
180
196
|
/**
|
@@ -259,6 +275,11 @@ export interface ValidationStream extends BaseStream {
|
|
259
275
|
* validator is using a token, this is an ephemeral public key.
|
260
276
|
*/
|
261
277
|
validation_public_key: string
|
278
|
+
|
279
|
+
/**
|
280
|
+
* The network from which the validations stream is received.
|
281
|
+
*/
|
282
|
+
network_id?: number
|
262
283
|
}
|
263
284
|
|
264
285
|
/**
|
@@ -8,6 +8,9 @@ import {
|
|
8
8
|
validateOptionalField,
|
9
9
|
isString,
|
10
10
|
isNumber,
|
11
|
+
MAX_MPT_META_BYTE_LENGTH,
|
12
|
+
MPT_META_WARNING_HEADER,
|
13
|
+
validateMPTokenMetadata,
|
11
14
|
} from './common'
|
12
15
|
import type { TransactionMetadataBase } from './metadata'
|
13
16
|
|
@@ -104,10 +107,18 @@ export interface MPTokenIssuanceCreate extends BaseTransaction {
|
|
104
107
|
* The field must NOT be present if the `tfMPTCanTransfer` flag is not set.
|
105
108
|
*/
|
106
109
|
TransferFee?: number
|
110
|
+
|
107
111
|
/**
|
108
|
-
*
|
112
|
+
* Optional arbitrary metadata about this issuance, encoded as a hex string and limited to 1024 bytes.
|
113
|
+
*
|
114
|
+
* The decoded value must be a UTF-8 encoded JSON object that adheres to the
|
115
|
+
* XLS-89d MPTokenMetadata standard.
|
116
|
+
*
|
117
|
+
* While adherence to the XLS-89d format is not mandatory, non-compliant metadata
|
118
|
+
* may not be discoverable by ecosystem tools such as explorers and indexers.
|
109
119
|
*/
|
110
|
-
MPTokenMetadata?: string
|
120
|
+
MPTokenMetadata?: string
|
121
|
+
|
111
122
|
Flags?: number | MPTokenIssuanceCreateFlagsInterface
|
112
123
|
}
|
113
124
|
|
@@ -131,15 +142,13 @@ export function validateMPTokenIssuanceCreate(
|
|
131
142
|
validateOptionalField(tx, 'TransferFee', isNumber)
|
132
143
|
validateOptionalField(tx, 'AssetScale', isNumber)
|
133
144
|
|
134
|
-
if (
|
145
|
+
if (
|
146
|
+
typeof tx.MPTokenMetadata === 'string' &&
|
147
|
+
(!isHex(tx.MPTokenMetadata) ||
|
148
|
+
tx.MPTokenMetadata.length / 2 > MAX_MPT_META_BYTE_LENGTH)
|
149
|
+
) {
|
135
150
|
throw new ValidationError(
|
136
|
-
|
137
|
-
)
|
138
|
-
}
|
139
|
-
|
140
|
-
if (typeof tx.MPTokenMetadata === 'string' && !isHex(tx.MPTokenMetadata)) {
|
141
|
-
throw new ValidationError(
|
142
|
-
'MPTokenIssuanceCreate: MPTokenMetadata must be in hex format',
|
151
|
+
`MPTokenIssuanceCreate: MPTokenMetadata (hex format) must be non-empty and no more than ${MAX_MPT_META_BYTE_LENGTH} bytes.`,
|
143
152
|
)
|
144
153
|
}
|
145
154
|
|
@@ -178,5 +187,19 @@ export function validateMPTokenIssuanceCreate(
|
|
178
187
|
)
|
179
188
|
}
|
180
189
|
}
|
190
|
+
|
191
|
+
if (tx.MPTokenMetadata != null) {
|
192
|
+
const validationMessages = validateMPTokenMetadata(tx.MPTokenMetadata)
|
193
|
+
|
194
|
+
if (validationMessages.length > 0) {
|
195
|
+
const message = [
|
196
|
+
MPT_META_WARNING_HEADER,
|
197
|
+
...validationMessages.map((msg) => `- ${msg}`),
|
198
|
+
].join('\n')
|
199
|
+
|
200
|
+
// eslint-disable-next-line no-console -- Required here.
|
201
|
+
console.warn(message)
|
202
|
+
}
|
203
|
+
}
|
181
204
|
}
|
182
205
|
/* eslint-enable max-lines-per-function */
|
@@ -61,6 +61,8 @@ export enum AccountSetAsfFlags {
|
|
61
61
|
asfDisallowIncomingTrustline = 15,
|
62
62
|
/** Permanently gain the ability to claw back issued IOUs */
|
63
63
|
asfAllowTrustLineClawback = 16,
|
64
|
+
/** Issuers allow their IOUs to be used as escrow amounts */
|
65
|
+
asfAllowTrustLineLocking = 17,
|
64
66
|
}
|
65
67
|
|
66
68
|
/**
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/* eslint-disable max-lines -- common utility file */
|
2
|
-
import { HEX_REGEX } from '@xrplf/isomorphic/utils'
|
2
|
+
import { HEX_REGEX, hexToString } from '@xrplf/isomorphic/utils'
|
3
3
|
import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec'
|
4
4
|
import { TRANSACTION_TYPES } from 'ripple-binary-codec'
|
5
5
|
|
@@ -12,6 +12,7 @@ import {
|
|
12
12
|
IssuedCurrency,
|
13
13
|
IssuedCurrencyAmount,
|
14
14
|
MPTAmount,
|
15
|
+
MPTokenMetadata,
|
15
16
|
Memo,
|
16
17
|
Signer,
|
17
18
|
XChainBridge,
|
@@ -22,10 +23,50 @@ const MEMO_SIZE = 3
|
|
22
23
|
export const MAX_AUTHORIZED_CREDENTIALS = 8
|
23
24
|
const MAX_CREDENTIAL_BYTE_LENGTH = 64
|
24
25
|
const MAX_CREDENTIAL_TYPE_LENGTH = MAX_CREDENTIAL_BYTE_LENGTH * 2
|
26
|
+
export const MAX_MPT_META_BYTE_LENGTH = 1024
|
25
27
|
|
26
28
|
// Used for Vault transactions
|
27
29
|
export const VAULT_DATA_MAX_BYTE_LENGTH = 256
|
28
30
|
|
31
|
+
// To validate MPTokenMetadata as per XLS-89d
|
32
|
+
const TICKER_REGEX = /^[A-Z0-9]{1,6}$/u
|
33
|
+
|
34
|
+
const MAX_MPT_META_TOP_LEVEL_FIELD_COUNT = 9
|
35
|
+
|
36
|
+
const MPT_META_URL_FIELD_COUNT = 3
|
37
|
+
|
38
|
+
const MPT_META_REQUIRED_FIELDS = [
|
39
|
+
'ticker',
|
40
|
+
'name',
|
41
|
+
'icon',
|
42
|
+
'asset_class',
|
43
|
+
'issuer_name',
|
44
|
+
]
|
45
|
+
|
46
|
+
const MPT_META_ASSET_CLASSES = [
|
47
|
+
'rwa',
|
48
|
+
'memes',
|
49
|
+
'wrapped',
|
50
|
+
'gaming',
|
51
|
+
'defi',
|
52
|
+
'other',
|
53
|
+
]
|
54
|
+
|
55
|
+
const MPT_META_ASSET_SUB_CLASSES = [
|
56
|
+
'stablecoin',
|
57
|
+
'commodity',
|
58
|
+
'real_estate',
|
59
|
+
'private_credit',
|
60
|
+
'equity',
|
61
|
+
'treasury',
|
62
|
+
'other',
|
63
|
+
]
|
64
|
+
|
65
|
+
export const MPT_META_WARNING_HEADER =
|
66
|
+
'MPTokenMetadata is not properly formatted as JSON as per the XLS-89d standard. ' +
|
67
|
+
"While adherence to this standard is not mandatory, such non-compliant MPToken's might not be discoverable " +
|
68
|
+
'by Explorers and Indexers in the XRPL ecosystem.'
|
69
|
+
|
29
70
|
function isMemo(obj: unknown): obj is Memo {
|
30
71
|
if (!isRecord(obj)) {
|
31
72
|
return false
|
@@ -683,3 +724,197 @@ export function containsDuplicates(
|
|
683
724
|
|
684
725
|
return false
|
685
726
|
}
|
727
|
+
|
728
|
+
const _DOMAIN_ID_LENGTH = 64
|
729
|
+
|
730
|
+
/**
|
731
|
+
* Utility method used across OfferCreate and Payment transactions to validate the DomainID.
|
732
|
+
*
|
733
|
+
* @param domainID - The domainID is a 64-character string that is used to identify a domain.
|
734
|
+
*
|
735
|
+
* @returns true if the domainID is a valid 64-character string, false otherwise
|
736
|
+
*/
|
737
|
+
export function isDomainID(domainID: unknown): domainID is string {
|
738
|
+
return (
|
739
|
+
isString(domainID) &&
|
740
|
+
domainID.length === _DOMAIN_ID_LENGTH &&
|
741
|
+
isHex(domainID)
|
742
|
+
)
|
743
|
+
}
|
744
|
+
|
745
|
+
/* eslint-disable max-lines-per-function -- Required here as structure validation is verbose. */
|
746
|
+
/* eslint-disable max-statements -- Required here as structure validation is verbose. */
|
747
|
+
|
748
|
+
/**
|
749
|
+
* Validates if MPTokenMetadata adheres to XLS-89d standard.
|
750
|
+
*
|
751
|
+
* @param input - Hex encoded MPTokenMetadata.
|
752
|
+
* @returns Validation messages if MPTokenMetadata does not adheres to XLS-89d standard.
|
753
|
+
*/
|
754
|
+
export function validateMPTokenMetadata(input: string): string[] {
|
755
|
+
const validationMessages: string[] = []
|
756
|
+
|
757
|
+
if (!isHex(input)) {
|
758
|
+
validationMessages.push(`MPTokenMetadata must be in hex format.`)
|
759
|
+
return validationMessages
|
760
|
+
}
|
761
|
+
|
762
|
+
if (input.length / 2 > MAX_MPT_META_BYTE_LENGTH) {
|
763
|
+
validationMessages.push(
|
764
|
+
`MPTokenMetadata must be max ${MAX_MPT_META_BYTE_LENGTH} bytes.`,
|
765
|
+
)
|
766
|
+
return validationMessages
|
767
|
+
}
|
768
|
+
|
769
|
+
let jsonMetaData: unknown
|
770
|
+
|
771
|
+
try {
|
772
|
+
jsonMetaData = JSON.parse(hexToString(input))
|
773
|
+
} catch (err) {
|
774
|
+
validationMessages.push(
|
775
|
+
`MPTokenMetadata is not properly formatted as JSON - ${String(err)}`,
|
776
|
+
)
|
777
|
+
return validationMessages
|
778
|
+
}
|
779
|
+
|
780
|
+
if (
|
781
|
+
jsonMetaData == null ||
|
782
|
+
typeof jsonMetaData !== 'object' ||
|
783
|
+
Array.isArray(jsonMetaData)
|
784
|
+
) {
|
785
|
+
validationMessages.push(
|
786
|
+
'MPTokenMetadata is not properly formatted as per XLS-89d.',
|
787
|
+
)
|
788
|
+
return validationMessages
|
789
|
+
}
|
790
|
+
|
791
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- It must be some JSON object.
|
792
|
+
const obj = jsonMetaData as Record<string, unknown>
|
793
|
+
|
794
|
+
// validating structure
|
795
|
+
|
796
|
+
// check for maximum number of fields
|
797
|
+
const fieldCount = Object.keys(obj).length
|
798
|
+
if (fieldCount > MAX_MPT_META_TOP_LEVEL_FIELD_COUNT) {
|
799
|
+
validationMessages.push(
|
800
|
+
`MPTokenMetadata must not contain more than ${MAX_MPT_META_TOP_LEVEL_FIELD_COUNT} top-level fields (found ${fieldCount}).`,
|
801
|
+
)
|
802
|
+
return validationMessages
|
803
|
+
}
|
804
|
+
|
805
|
+
const incorrectRequiredFields = MPT_META_REQUIRED_FIELDS.filter(
|
806
|
+
(field) => !isString(obj[field]),
|
807
|
+
)
|
808
|
+
|
809
|
+
if (incorrectRequiredFields.length > 0) {
|
810
|
+
incorrectRequiredFields.forEach((field) =>
|
811
|
+
validationMessages.push(`${field} is required and must be string.`),
|
812
|
+
)
|
813
|
+
return validationMessages
|
814
|
+
}
|
815
|
+
|
816
|
+
if (obj.desc != null && !isString(obj.desc)) {
|
817
|
+
validationMessages.push(`desc must be a string.`)
|
818
|
+
return validationMessages
|
819
|
+
}
|
820
|
+
|
821
|
+
if (obj.asset_subclass != null && !isString(obj.asset_subclass)) {
|
822
|
+
validationMessages.push(`asset_subclass must be a string.`)
|
823
|
+
return validationMessages
|
824
|
+
}
|
825
|
+
|
826
|
+
if (
|
827
|
+
obj.additional_info != null &&
|
828
|
+
!isString(obj.additional_info) &&
|
829
|
+
!isRecord(obj.additional_info)
|
830
|
+
) {
|
831
|
+
validationMessages.push(`additional_info must be a string or JSON object.`)
|
832
|
+
return validationMessages
|
833
|
+
}
|
834
|
+
|
835
|
+
if (obj.urls != null) {
|
836
|
+
if (!Array.isArray(obj.urls)) {
|
837
|
+
validationMessages.push('urls must be an array as per XLS-89d.')
|
838
|
+
return validationMessages
|
839
|
+
}
|
840
|
+
if (!obj.urls.every(isValidMPTokenMetadataUrlStructure)) {
|
841
|
+
validationMessages.push(
|
842
|
+
'One or more urls are not structured per XLS-89d.',
|
843
|
+
)
|
844
|
+
return validationMessages
|
845
|
+
}
|
846
|
+
}
|
847
|
+
|
848
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Required here.
|
849
|
+
const mptMPTokenMetadata = obj as unknown as MPTokenMetadata
|
850
|
+
|
851
|
+
// validating content
|
852
|
+
if (!TICKER_REGEX.test(mptMPTokenMetadata.ticker)) {
|
853
|
+
validationMessages.push(
|
854
|
+
`ticker should have uppercase letters (A-Z) and digits (0-9) only. Max 6 characters recommended.`,
|
855
|
+
)
|
856
|
+
}
|
857
|
+
|
858
|
+
if (!mptMPTokenMetadata.icon.startsWith('https://')) {
|
859
|
+
validationMessages.push(`icon should be a valid https url.`)
|
860
|
+
}
|
861
|
+
|
862
|
+
if (
|
863
|
+
!MPT_META_ASSET_CLASSES.includes(
|
864
|
+
mptMPTokenMetadata.asset_class.toLowerCase(),
|
865
|
+
)
|
866
|
+
) {
|
867
|
+
validationMessages.push(
|
868
|
+
`asset_class should be one of ${MPT_META_ASSET_CLASSES.join(', ')}.`,
|
869
|
+
)
|
870
|
+
}
|
871
|
+
|
872
|
+
if (
|
873
|
+
mptMPTokenMetadata.asset_subclass != null &&
|
874
|
+
!MPT_META_ASSET_SUB_CLASSES.includes(
|
875
|
+
mptMPTokenMetadata.asset_subclass.toLowerCase(),
|
876
|
+
)
|
877
|
+
) {
|
878
|
+
validationMessages.push(
|
879
|
+
`asset_subclass should be one of ${MPT_META_ASSET_SUB_CLASSES.join(
|
880
|
+
', ',
|
881
|
+
)}.`,
|
882
|
+
)
|
883
|
+
}
|
884
|
+
|
885
|
+
if (
|
886
|
+
mptMPTokenMetadata.asset_class.toLowerCase() === 'rwa' &&
|
887
|
+
mptMPTokenMetadata.asset_subclass == null
|
888
|
+
) {
|
889
|
+
validationMessages.push(
|
890
|
+
`asset_subclass is required when asset_class is rwa.`,
|
891
|
+
)
|
892
|
+
}
|
893
|
+
|
894
|
+
if (
|
895
|
+
mptMPTokenMetadata.urls != null &&
|
896
|
+
!mptMPTokenMetadata.urls.every((ele) => ele.url.startsWith('https://'))
|
897
|
+
) {
|
898
|
+
validationMessages.push(`url should be a valid https url.`)
|
899
|
+
}
|
900
|
+
|
901
|
+
return validationMessages
|
902
|
+
}
|
903
|
+
/* eslint-enable max-lines-per-function */
|
904
|
+
/* eslint-enable max-statements */
|
905
|
+
|
906
|
+
function isValidMPTokenMetadataUrlStructure(input: unknown): boolean {
|
907
|
+
if (input == null) {
|
908
|
+
return false
|
909
|
+
}
|
910
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Required here.
|
911
|
+
const obj = input as Record<string, unknown>
|
912
|
+
|
913
|
+
return (
|
914
|
+
typeof obj === 'object' &&
|
915
|
+
isString(obj.url) &&
|
916
|
+
isString(obj.type) &&
|
917
|
+
isString(obj.title) &&
|
918
|
+
Object.keys(obj).length === MPT_META_URL_FIELD_COUNT
|
919
|
+
)
|
920
|
+
}
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import { ValidationError } from '../../errors'
|
2
|
+
import { Amount, MPTAmount } from '../common'
|
2
3
|
|
3
4
|
import {
|
4
5
|
Account,
|
5
6
|
BaseTransaction,
|
6
7
|
isAccount,
|
8
|
+
isAmount,
|
7
9
|
isNumber,
|
8
10
|
validateBaseTransaction,
|
9
11
|
validateOptionalField,
|
@@ -18,11 +20,12 @@ import {
|
|
18
20
|
export interface EscrowCreate extends BaseTransaction {
|
19
21
|
TransactionType: 'EscrowCreate'
|
20
22
|
/**
|
21
|
-
*
|
22
|
-
* Once escrowed,
|
23
|
-
*
|
23
|
+
* The amount to deduct from the sender's balance and and set aside in escrow.
|
24
|
+
* Once escrowed, this amount can either go to the Destination address (after any Finish times/conditions)
|
25
|
+
* or returned to the sender (after any cancellation times/conditions). Can represent XRP, in drops,
|
26
|
+
* an IOU token, or an MPT. Must always be a positive value.
|
24
27
|
*/
|
25
|
-
Amount:
|
28
|
+
Amount: Amount | MPTAmount
|
26
29
|
/** Address to receive escrowed XRP. */
|
27
30
|
Destination: Account
|
28
31
|
/**
|
@@ -62,14 +65,7 @@ export interface EscrowCreate extends BaseTransaction {
|
|
62
65
|
export function validateEscrowCreate(tx: Record<string, unknown>): void {
|
63
66
|
validateBaseTransaction(tx)
|
64
67
|
|
65
|
-
|
66
|
-
throw new ValidationError('EscrowCreate: missing field Amount')
|
67
|
-
}
|
68
|
-
|
69
|
-
if (typeof tx.Amount !== 'string') {
|
70
|
-
throw new ValidationError('EscrowCreate: Amount must be a string')
|
71
|
-
}
|
72
|
-
|
68
|
+
validateRequiredField(tx, 'Amount', isAmount)
|
73
69
|
validateRequiredField(tx, 'Destination', isAccount)
|
74
70
|
validateOptionalField(tx, 'DestinationTag', isNumber)
|
75
71
|
|
@@ -9,6 +9,7 @@ import {
|
|
9
9
|
validateRequiredField,
|
10
10
|
MAX_AUTHORIZED_CREDENTIALS,
|
11
11
|
} from './common'
|
12
|
+
import { TransactionMetadataBase } from './metadata'
|
12
13
|
|
13
14
|
/**
|
14
15
|
* Deliver XRP from a held payment to the recipient.
|
@@ -42,6 +43,12 @@ export interface EscrowFinish extends BaseTransaction {
|
|
42
43
|
ComputationAllowance?: number
|
43
44
|
}
|
44
45
|
|
46
|
+
export interface EscrowFinishMetadata extends TransactionMetadataBase {
|
47
|
+
// if ComputationAllowance is present and the Smart Escrow runs
|
48
|
+
GasUsed?: number
|
49
|
+
WasmReturnCode?: number
|
50
|
+
}
|
51
|
+
|
45
52
|
/**
|
46
53
|
* Verify the form and type of an EscrowFinish at runtime.
|
47
54
|
*
|
@@ -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,
|
@@ -105,4 +106,6 @@ export type TransactionMetadata<T extends BaseTransaction = Transaction> =
|
|
105
106
|
? NFTokenCancelOfferMetadata
|
106
107
|
: T extends MPTokenIssuanceCreate
|
107
108
|
? MPTokenIssuanceCreateMetadata
|
109
|
+
: T extends EscrowFinish
|
110
|
+
? EscrowFinishMetadata
|
108
111
|
: TransactionMetadataBase
|
@@ -1,11 +1,14 @@
|
|
1
1
|
import { ValidationError } from '../../errors'
|
2
2
|
import { Amount } from '../common'
|
3
|
+
import { hasFlag } from '../utils'
|
3
4
|
|
4
5
|
import {
|
5
6
|
BaseTransaction,
|
6
7
|
GlobalFlagsInterface,
|
7
8
|
validateBaseTransaction,
|
8
9
|
isAmount,
|
10
|
+
validateOptionalField,
|
11
|
+
isDomainID,
|
9
12
|
} from './common'
|
10
13
|
|
11
14
|
/**
|
@@ -42,6 +45,11 @@ export enum OfferCreateFlags {
|
|
42
45
|
* the TakerPays amount in exchange.
|
43
46
|
*/
|
44
47
|
tfSell = 0x00080000,
|
48
|
+
/**
|
49
|
+
* Indicates the offer is hybrid. (meaning it is part of both a domain and open order book)
|
50
|
+
* This flag cannot be set if the offer doesn't have a DomainID
|
51
|
+
*/
|
52
|
+
tfHybrid = 0x00100000,
|
45
53
|
}
|
46
54
|
|
47
55
|
/**
|
@@ -83,6 +91,7 @@ export interface OfferCreateFlagsInterface extends GlobalFlagsInterface {
|
|
83
91
|
tfImmediateOrCancel?: boolean
|
84
92
|
tfFillOrKill?: boolean
|
85
93
|
tfSell?: boolean
|
94
|
+
tfHybrid?: boolean
|
86
95
|
}
|
87
96
|
|
88
97
|
/**
|
@@ -106,6 +115,8 @@ export interface OfferCreate extends BaseTransaction {
|
|
106
115
|
TakerGets: Amount
|
107
116
|
/** The amount and type of currency being requested by the offer creator. */
|
108
117
|
TakerPays: Amount
|
118
|
+
/** The domain that the offer must be a part of. */
|
119
|
+
DomainID?: string
|
109
120
|
}
|
110
121
|
|
111
122
|
/**
|
@@ -140,4 +151,18 @@ export function validateOfferCreate(tx: Record<string, unknown>): void {
|
|
140
151
|
if (tx.OfferSequence !== undefined && typeof tx.OfferSequence !== 'number') {
|
141
152
|
throw new ValidationError('OfferCreate: invalid OfferSequence')
|
142
153
|
}
|
154
|
+
|
155
|
+
validateOptionalField(tx, 'DomainID', isDomainID, {
|
156
|
+
txType: 'OfferCreate',
|
157
|
+
paramName: 'DomainID',
|
158
|
+
})
|
159
|
+
|
160
|
+
if (
|
161
|
+
tx.DomainID == null &&
|
162
|
+
hasFlag(tx, OfferCreateFlags.tfHybrid, 'tfHybrid')
|
163
|
+
) {
|
164
|
+
throw new ValidationError(
|
165
|
+
'OfferCreate: tfHybrid flag cannot be set if DomainID is not present',
|
166
|
+
)
|
167
|
+
}
|
143
168
|
}
|
@@ -8,6 +8,7 @@ import {
|
|
8
8
|
GlobalFlagsInterface,
|
9
9
|
validateBaseTransaction,
|
10
10
|
isAccount,
|
11
|
+
isDomainID,
|
11
12
|
validateRequiredField,
|
12
13
|
validateOptionalField,
|
13
14
|
isNumber,
|
@@ -160,6 +161,18 @@ export interface Payment extends BaseTransaction {
|
|
160
161
|
* The credentials included must not be expired.
|
161
162
|
*/
|
162
163
|
CredentialIDs?: string[]
|
164
|
+
/**
|
165
|
+
* The domain the sender intends to use. Both the sender and destination must
|
166
|
+
* be part of this domain. The DomainID can be included if the sender intends
|
167
|
+
* it to be a cross-currency payment (i.e. if the payment is going to interact
|
168
|
+
* with the DEX). The domain will only play it's role if there is a path that
|
169
|
+
* crossing an orderbook.
|
170
|
+
*
|
171
|
+
* Note: it's still possible that DomainID is included but the payment does
|
172
|
+
* not interact with DEX, it simply means that the DomainID will be ignored
|
173
|
+
* during payment paths.
|
174
|
+
*/
|
175
|
+
DomainID?: string
|
163
176
|
Flags?: number | PaymentFlagsInterface
|
164
177
|
}
|
165
178
|
|
@@ -199,6 +212,11 @@ export function validatePayment(tx: Record<string, unknown>): void {
|
|
199
212
|
throw new ValidationError('PaymentTransaction: InvoiceID must be a string')
|
200
213
|
}
|
201
214
|
|
215
|
+
validateOptionalField(tx, 'DomainID', isDomainID, {
|
216
|
+
txType: 'PaymentTransaction',
|
217
|
+
paramName: 'DomainID',
|
218
|
+
})
|
219
|
+
|
202
220
|
if (tx.Paths !== undefined && !isPaths(tx.Paths)) {
|
203
221
|
throw new ValidationError('PaymentTransaction: invalid Paths')
|
204
222
|
}
|
@@ -208,12 +226,6 @@ export function validatePayment(tx: Record<string, unknown>): void {
|
|
208
226
|
}
|
209
227
|
|
210
228
|
checkPartialPayment(tx)
|
211
|
-
|
212
|
-
if (tx.DeliverMax != null) {
|
213
|
-
throw new ValidationError(
|
214
|
-
'PaymentTransaction: Cannot have DeliverMax in a submitted transaction',
|
215
|
-
)
|
216
|
-
}
|
217
229
|
}
|
218
230
|
|
219
231
|
function checkPartialPayment(tx: Record<string, unknown>): void {
|