xrpl 4.4.0-smartescrow.0 → 4.4.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.
Files changed (195) 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 +407 -268
  4. package/build/xrpl-latest.js.map +1 -1
  5. package/dist/npm/Wallet/defaultFaucets.d.ts +1 -2
  6. package/dist/npm/Wallet/defaultFaucets.d.ts.map +1 -1
  7. package/dist/npm/Wallet/defaultFaucets.js +0 -3
  8. package/dist/npm/Wallet/defaultFaucets.js.map +1 -1
  9. package/dist/npm/models/common/index.d.ts +16 -0
  10. package/dist/npm/models/common/index.d.ts.map +1 -1
  11. package/dist/npm/models/ledger/AccountRoot.d.ts +3 -1
  12. package/dist/npm/models/ledger/AccountRoot.d.ts.map +1 -1
  13. package/dist/npm/models/ledger/AccountRoot.js +1 -0
  14. package/dist/npm/models/ledger/AccountRoot.js.map +1 -1
  15. package/dist/npm/models/ledger/DirectoryNode.d.ts +1 -0
  16. package/dist/npm/models/ledger/DirectoryNode.d.ts.map +1 -1
  17. package/dist/npm/models/ledger/Escrow.d.ts +2 -2
  18. package/dist/npm/models/ledger/Escrow.d.ts.map +1 -1
  19. package/dist/npm/models/ledger/FeeSettings.d.ts +0 -2
  20. package/dist/npm/models/ledger/FeeSettings.d.ts.map +1 -1
  21. package/dist/npm/models/ledger/MPToken.d.ts +1 -0
  22. package/dist/npm/models/ledger/MPToken.d.ts.map +1 -1
  23. package/dist/npm/models/ledger/MPTokenIssuance.d.ts +1 -0
  24. package/dist/npm/models/ledger/MPTokenIssuance.d.ts.map +1 -1
  25. package/dist/npm/models/ledger/Offer.d.ts +10 -1
  26. package/dist/npm/models/ledger/Offer.d.ts.map +1 -1
  27. package/dist/npm/models/ledger/Offer.js +1 -0
  28. package/dist/npm/models/ledger/Offer.js.map +1 -1
  29. package/dist/npm/models/methods/bookOffers.d.ts +1 -0
  30. package/dist/npm/models/methods/bookOffers.d.ts.map +1 -1
  31. package/dist/npm/models/methods/pathFind.d.ts +2 -0
  32. package/dist/npm/models/methods/pathFind.d.ts.map +1 -1
  33. package/dist/npm/models/methods/ripplePathFind.d.ts +1 -0
  34. package/dist/npm/models/methods/ripplePathFind.d.ts.map +1 -1
  35. package/dist/npm/models/methods/serverInfo.d.ts +0 -6
  36. package/dist/npm/models/methods/serverInfo.d.ts.map +1 -1
  37. package/dist/npm/models/methods/serverState.d.ts +0 -6
  38. package/dist/npm/models/methods/serverState.d.ts.map +1 -1
  39. package/dist/npm/models/methods/subscribe.d.ts +4 -0
  40. package/dist/npm/models/methods/subscribe.d.ts.map +1 -1
  41. package/dist/npm/models/transactions/MPTokenIssuanceCreate.d.ts +1 -1
  42. package/dist/npm/models/transactions/MPTokenIssuanceCreate.d.ts.map +1 -1
  43. package/dist/npm/models/transactions/MPTokenIssuanceCreate.js +14 -5
  44. package/dist/npm/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
  45. package/dist/npm/models/transactions/accountSet.d.ts +2 -1
  46. package/dist/npm/models/transactions/accountSet.d.ts.map +1 -1
  47. package/dist/npm/models/transactions/accountSet.js +1 -0
  48. package/dist/npm/models/transactions/accountSet.js.map +1 -1
  49. package/dist/npm/models/transactions/common.d.ts +4 -0
  50. package/dist/npm/models/transactions/common.d.ts.map +1 -1
  51. package/dist/npm/models/transactions/common.js +134 -1
  52. package/dist/npm/models/transactions/common.js.map +1 -1
  53. package/dist/npm/models/transactions/escrowCreate.d.ts +2 -3
  54. package/dist/npm/models/transactions/escrowCreate.d.ts.map +1 -1
  55. package/dist/npm/models/transactions/escrowCreate.js +3 -10
  56. package/dist/npm/models/transactions/escrowCreate.js.map +1 -1
  57. package/dist/npm/models/transactions/escrowFinish.d.ts +0 -1
  58. package/dist/npm/models/transactions/escrowFinish.d.ts.map +1 -1
  59. package/dist/npm/models/transactions/escrowFinish.js.map +1 -1
  60. package/dist/npm/models/transactions/index.d.ts +1 -1
  61. package/dist/npm/models/transactions/index.d.ts.map +1 -1
  62. package/dist/npm/models/transactions/index.js +2 -1
  63. package/dist/npm/models/transactions/index.js.map +1 -1
  64. package/dist/npm/models/transactions/offerCreate.d.ts +4 -1
  65. package/dist/npm/models/transactions/offerCreate.d.ts.map +1 -1
  66. package/dist/npm/models/transactions/offerCreate.js +10 -0
  67. package/dist/npm/models/transactions/offerCreate.js.map +1 -1
  68. package/dist/npm/models/transactions/payment.d.ts +1 -0
  69. package/dist/npm/models/transactions/payment.d.ts.map +1 -1
  70. package/dist/npm/models/transactions/payment.js +4 -3
  71. package/dist/npm/models/transactions/payment.js.map +1 -1
  72. package/dist/npm/models/transactions/vaultCreate.d.ts.map +1 -1
  73. package/dist/npm/models/transactions/vaultCreate.js +13 -4
  74. package/dist/npm/models/transactions/vaultCreate.js.map +1 -1
  75. package/dist/npm/models/transactions/vaultDeposit.d.ts +2 -2
  76. package/dist/npm/models/transactions/vaultDeposit.d.ts.map +1 -1
  77. package/dist/npm/models/transactions/vaultDeposit.js.map +1 -1
  78. package/dist/npm/models/transactions/vaultWithdraw.d.ts +2 -2
  79. package/dist/npm/models/transactions/vaultWithdraw.d.ts.map +1 -1
  80. package/dist/npm/models/transactions/vaultWithdraw.js.map +1 -1
  81. package/dist/npm/snippets/src/permissionedDEX.d.ts +2 -0
  82. package/dist/npm/snippets/src/permissionedDEX.d.ts.map +1 -0
  83. package/dist/npm/snippets/src/permissionedDEX.js +173 -0
  84. package/dist/npm/snippets/src/permissionedDEX.js.map +1 -0
  85. package/dist/npm/snippets/tsconfig.tsbuildinfo +1 -1
  86. package/dist/npm/src/Wallet/defaultFaucets.d.ts +1 -2
  87. package/dist/npm/src/Wallet/defaultFaucets.d.ts.map +1 -1
  88. package/dist/npm/src/Wallet/defaultFaucets.js +0 -3
  89. package/dist/npm/src/Wallet/defaultFaucets.js.map +1 -1
  90. package/dist/npm/src/models/common/index.d.ts +16 -0
  91. package/dist/npm/src/models/common/index.d.ts.map +1 -1
  92. package/dist/npm/src/models/ledger/AccountRoot.d.ts +3 -1
  93. package/dist/npm/src/models/ledger/AccountRoot.d.ts.map +1 -1
  94. package/dist/npm/src/models/ledger/AccountRoot.js +1 -0
  95. package/dist/npm/src/models/ledger/AccountRoot.js.map +1 -1
  96. package/dist/npm/src/models/ledger/DirectoryNode.d.ts +1 -0
  97. package/dist/npm/src/models/ledger/DirectoryNode.d.ts.map +1 -1
  98. package/dist/npm/src/models/ledger/Escrow.d.ts +2 -2
  99. package/dist/npm/src/models/ledger/Escrow.d.ts.map +1 -1
  100. package/dist/npm/src/models/ledger/FeeSettings.d.ts +0 -2
  101. package/dist/npm/src/models/ledger/FeeSettings.d.ts.map +1 -1
  102. package/dist/npm/src/models/ledger/MPToken.d.ts +1 -0
  103. package/dist/npm/src/models/ledger/MPToken.d.ts.map +1 -1
  104. package/dist/npm/src/models/ledger/MPTokenIssuance.d.ts +1 -0
  105. package/dist/npm/src/models/ledger/MPTokenIssuance.d.ts.map +1 -1
  106. package/dist/npm/src/models/ledger/Offer.d.ts +10 -1
  107. package/dist/npm/src/models/ledger/Offer.d.ts.map +1 -1
  108. package/dist/npm/src/models/ledger/Offer.js +1 -0
  109. package/dist/npm/src/models/ledger/Offer.js.map +1 -1
  110. package/dist/npm/src/models/methods/bookOffers.d.ts +1 -0
  111. package/dist/npm/src/models/methods/bookOffers.d.ts.map +1 -1
  112. package/dist/npm/src/models/methods/pathFind.d.ts +2 -0
  113. package/dist/npm/src/models/methods/pathFind.d.ts.map +1 -1
  114. package/dist/npm/src/models/methods/ripplePathFind.d.ts +1 -0
  115. package/dist/npm/src/models/methods/ripplePathFind.d.ts.map +1 -1
  116. package/dist/npm/src/models/methods/serverInfo.d.ts +0 -6
  117. package/dist/npm/src/models/methods/serverInfo.d.ts.map +1 -1
  118. package/dist/npm/src/models/methods/serverState.d.ts +0 -6
  119. package/dist/npm/src/models/methods/serverState.d.ts.map +1 -1
  120. package/dist/npm/src/models/methods/subscribe.d.ts +4 -0
  121. package/dist/npm/src/models/methods/subscribe.d.ts.map +1 -1
  122. package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.d.ts +1 -1
  123. package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.d.ts.map +1 -1
  124. package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.js +14 -5
  125. package/dist/npm/src/models/transactions/MPTokenIssuanceCreate.js.map +1 -1
  126. package/dist/npm/src/models/transactions/accountSet.d.ts +2 -1
  127. package/dist/npm/src/models/transactions/accountSet.d.ts.map +1 -1
  128. package/dist/npm/src/models/transactions/accountSet.js +1 -0
  129. package/dist/npm/src/models/transactions/accountSet.js.map +1 -1
  130. package/dist/npm/src/models/transactions/common.d.ts +4 -0
  131. package/dist/npm/src/models/transactions/common.d.ts.map +1 -1
  132. package/dist/npm/src/models/transactions/common.js +134 -1
  133. package/dist/npm/src/models/transactions/common.js.map +1 -1
  134. package/dist/npm/src/models/transactions/escrowCreate.d.ts +2 -3
  135. package/dist/npm/src/models/transactions/escrowCreate.d.ts.map +1 -1
  136. package/dist/npm/src/models/transactions/escrowCreate.js +3 -10
  137. package/dist/npm/src/models/transactions/escrowCreate.js.map +1 -1
  138. package/dist/npm/src/models/transactions/escrowFinish.d.ts +0 -1
  139. package/dist/npm/src/models/transactions/escrowFinish.d.ts.map +1 -1
  140. package/dist/npm/src/models/transactions/escrowFinish.js.map +1 -1
  141. package/dist/npm/src/models/transactions/index.d.ts +1 -1
  142. package/dist/npm/src/models/transactions/index.d.ts.map +1 -1
  143. package/dist/npm/src/models/transactions/index.js +2 -1
  144. package/dist/npm/src/models/transactions/index.js.map +1 -1
  145. package/dist/npm/src/models/transactions/offerCreate.d.ts +4 -1
  146. package/dist/npm/src/models/transactions/offerCreate.d.ts.map +1 -1
  147. package/dist/npm/src/models/transactions/offerCreate.js +10 -0
  148. package/dist/npm/src/models/transactions/offerCreate.js.map +1 -1
  149. package/dist/npm/src/models/transactions/payment.d.ts +1 -0
  150. package/dist/npm/src/models/transactions/payment.d.ts.map +1 -1
  151. package/dist/npm/src/models/transactions/payment.js +4 -3
  152. package/dist/npm/src/models/transactions/payment.js.map +1 -1
  153. package/dist/npm/src/models/transactions/vaultCreate.d.ts.map +1 -1
  154. package/dist/npm/src/models/transactions/vaultCreate.js +13 -4
  155. package/dist/npm/src/models/transactions/vaultCreate.js.map +1 -1
  156. package/dist/npm/src/models/transactions/vaultDeposit.d.ts +2 -2
  157. package/dist/npm/src/models/transactions/vaultDeposit.d.ts.map +1 -1
  158. package/dist/npm/src/models/transactions/vaultDeposit.js.map +1 -1
  159. package/dist/npm/src/models/transactions/vaultWithdraw.d.ts +2 -2
  160. package/dist/npm/src/models/transactions/vaultWithdraw.d.ts.map +1 -1
  161. package/dist/npm/src/models/transactions/vaultWithdraw.js.map +1 -1
  162. package/dist/npm/src/sugar/autofill.d.ts.map +1 -1
  163. package/dist/npm/src/sugar/autofill.js +11 -32
  164. package/dist/npm/src/sugar/autofill.js.map +1 -1
  165. package/dist/npm/sugar/autofill.d.ts.map +1 -1
  166. package/dist/npm/sugar/autofill.js +11 -32
  167. package/dist/npm/sugar/autofill.js.map +1 -1
  168. package/package.json +4 -4
  169. package/src/Wallet/defaultFaucets.ts +0 -5
  170. package/src/models/common/index.ts +25 -0
  171. package/src/models/ledger/AccountRoot.ts +10 -0
  172. package/src/models/ledger/DirectoryNode.ts +3 -0
  173. package/src/models/ledger/Escrow.ts +12 -3
  174. package/src/models/ledger/FeeSettings.ts +0 -4
  175. package/src/models/ledger/MPToken.ts +1 -0
  176. package/src/models/ledger/MPTokenIssuance.ts +1 -0
  177. package/src/models/ledger/Offer.ts +21 -0
  178. package/src/models/methods/bookOffers.ts +7 -0
  179. package/src/models/methods/pathFind.ts +10 -0
  180. package/src/models/methods/ripplePathFind.ts +5 -0
  181. package/src/models/methods/serverInfo.ts +0 -9
  182. package/src/models/methods/serverState.ts +0 -10
  183. package/src/models/methods/subscribe.ts +21 -0
  184. package/src/models/transactions/MPTokenIssuanceCreate.ts +33 -10
  185. package/src/models/transactions/accountSet.ts +2 -0
  186. package/src/models/transactions/common.ts +236 -1
  187. package/src/models/transactions/escrowCreate.ts +10 -22
  188. package/src/models/transactions/escrowFinish.ts +0 -2
  189. package/src/models/transactions/index.ts +1 -1
  190. package/src/models/transactions/offerCreate.ts +25 -0
  191. package/src/models/transactions/payment.ts +18 -6
  192. package/src/models/transactions/vaultCreate.ts +30 -6
  193. package/src/models/transactions/vaultDeposit.ts +3 -2
  194. package/src/models/transactions/vaultWithdraw.ts +3 -2
  195. package/src/sugar/autofill.ts +25 -39
@@ -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
- * Arbitrary metadata about this issuance, in hex format.
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 | null
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 (typeof tx.MPTokenMetadata === 'string' && tx.MPTokenMetadata === '') {
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
- 'MPTokenIssuanceCreate: MPTokenMetadata must not be empty string',
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
- * Amount of XRP, in drops, to deduct from the sender's balance and escrow.
22
- * Once escrowed, the XRP can either go to the Destination address (after the.
23
- * FinishAfter time) or returned to the sender (after the CancelAfter time).
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: string
28
+ Amount: Amount | MPTAmount
26
29
  /** Address to receive escrowed XRP. */
27
30
  Destination: Account
28
31
  /**
@@ -47,10 +50,6 @@ export interface EscrowCreate extends BaseTransaction {
47
50
  * payment, such as a hosted recipient at the destination address.
48
51
  */
49
52
  DestinationTag?: number
50
-
51
- FinishFunction?: string
52
-
53
- Data?: string
54
53
  }
55
54
 
56
55
  /**
@@ -62,14 +61,7 @@ export interface EscrowCreate extends BaseTransaction {
62
61
  export function validateEscrowCreate(tx: Record<string, unknown>): void {
63
62
  validateBaseTransaction(tx)
64
63
 
65
- if (tx.Amount === undefined) {
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
-
64
+ validateRequiredField(tx, 'Amount', isAmount)
73
65
  validateRequiredField(tx, 'Destination', isAccount)
74
66
  validateOptionalField(tx, 'DestinationTag', isNumber)
75
67
 
@@ -79,13 +71,9 @@ export function validateEscrowCreate(tx: Record<string, unknown>): void {
79
71
  )
80
72
  }
81
73
 
82
- if (
83
- tx.FinishAfter === undefined &&
84
- tx.Condition === undefined &&
85
- tx.FinishFunction === undefined
86
- ) {
74
+ if (tx.FinishAfter === undefined && tx.Condition === undefined) {
87
75
  throw new ValidationError(
88
- 'EscrowCreate: Either FinishAfter, Condition, or FinishFunction must be specified',
76
+ 'EscrowCreate: Either Condition or FinishAfter must be specified',
89
77
  )
90
78
  }
91
79
 
@@ -38,8 +38,6 @@ export interface EscrowFinish extends BaseTransaction {
38
38
  * The credentials included must not be expired.
39
39
  */
40
40
  CredentialIDs?: string[]
41
-
42
- ComputationAllowance?: number
43
41
  }
44
42
 
45
43
  /**
@@ -1,4 +1,4 @@
1
- export { BaseTransaction, isMPTAmount } from './common'
1
+ export { BaseTransaction, isMPTAmount, validateMPTokenMetadata } from './common'
2
2
  export {
3
3
  validate,
4
4
  PseudoTransaction,
@@ -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 {
@@ -14,10 +14,11 @@ import {
14
14
  VAULT_DATA_MAX_BYTE_LENGTH,
15
15
  XRPLNumber,
16
16
  isXRPLNumber,
17
+ MAX_MPT_META_BYTE_LENGTH,
18
+ MPT_META_WARNING_HEADER,
19
+ validateMPTokenMetadata,
17
20
  } from './common'
18
21
 
19
- const META_MAX_BYTE_LENGTH = 1024
20
-
21
22
  /**
22
23
  * Enum representing withdrawal strategies for a Vault.
23
24
  */
@@ -71,6 +72,12 @@ export interface VaultCreate extends BaseTransaction {
71
72
 
72
73
  /**
73
74
  * Arbitrary metadata about the share MPT, in hex format, limited to 1024 bytes.
75
+ *
76
+ * The decoded value must be a UTF-8 encoded JSON object that adheres to the
77
+ * XLS-89d MPTokenMetadata standard.
78
+ *
79
+ * While adherence to the XLS-89d format is not mandatory, non-compliant metadata
80
+ * may not be discoverable by ecosystem tools such as explorers and indexers.
74
81
  */
75
82
  MPTokenMetadata?: string
76
83
 
@@ -85,13 +92,14 @@ export interface VaultCreate extends BaseTransaction {
85
92
  DomainID?: string
86
93
  }
87
94
 
95
+ /* eslint-disable max-lines-per-function -- Not needed to reduce function */
96
+ /* eslint-disable max-statements -- required to do all field validations */
88
97
  /**
89
98
  * Verify the form and type of an {@link VaultCreate} at runtime.
90
99
  *
91
100
  * @param tx - A {@link VaultCreate} Transaction.
92
101
  * @throws When the {@link VaultCreate} is malformed.
93
102
  */
94
- // eslint-disable-next-line max-lines-per-function -- required to do all field validations
95
103
  export function validateVaultCreate(tx: Record<string, unknown>): void {
96
104
  validateBaseTransaction(tx)
97
105
 
@@ -119,13 +127,13 @@ export function validateVaultCreate(tx: Record<string, unknown>): void {
119
127
  const metaHex = tx.MPTokenMetadata
120
128
  if (!isHex(metaHex)) {
121
129
  throw new ValidationError(
122
- 'VaultCreate: MPTokenMetadata must be a valid hex string',
130
+ 'VaultCreate: MPTokenMetadata must be a valid non-empty hex string',
123
131
  )
124
132
  }
125
133
  const metaByteLength = metaHex.length / 2
126
- if (metaByteLength > META_MAX_BYTE_LENGTH) {
134
+ if (metaByteLength > MAX_MPT_META_BYTE_LENGTH) {
127
135
  throw new ValidationError(
128
- `VaultCreate: MPTokenMetadata exceeds ${META_MAX_BYTE_LENGTH} bytes (actual: ${metaByteLength})`,
136
+ `VaultCreate: MPTokenMetadata exceeds ${MAX_MPT_META_BYTE_LENGTH} bytes (actual: ${metaByteLength})`,
129
137
  )
130
138
  }
131
139
  }
@@ -139,4 +147,20 @@ export function validateVaultCreate(tx: Record<string, unknown>): void {
139
147
  'VaultCreate: Cannot set DomainID unless tfVaultPrivate flag is set.',
140
148
  )
141
149
  }
150
+
151
+ if (tx.MPTokenMetadata != null) {
152
+ const validationMessages = validateMPTokenMetadata(tx.MPTokenMetadata)
153
+
154
+ if (validationMessages.length > 0) {
155
+ const message = [
156
+ MPT_META_WARNING_HEADER,
157
+ ...validationMessages.map((msg) => `- ${msg}`),
158
+ ].join('\n')
159
+
160
+ // eslint-disable-next-line no-console -- Required here.
161
+ console.warn(message)
162
+ }
163
+ }
142
164
  }
165
+ /* eslint-enable max-lines-per-function */
166
+ /* eslint-enable max-statements */
@@ -1,4 +1,4 @@
1
- import { Amount } from '../common'
1
+ import { Amount, MPTAmount } from '../common'
2
2
 
3
3
  import {
4
4
  BaseTransaction,
@@ -24,7 +24,8 @@ export interface VaultDeposit extends BaseTransaction {
24
24
  /**
25
25
  * Asset amount to deposit.
26
26
  */
27
- Amount: Amount
27
+ // TODO: remove MPTAmount when MPTv2 is released
28
+ Amount: Amount | MPTAmount
28
29
  }
29
30
 
30
31
  /**
@@ -1,4 +1,4 @@
1
- import { Amount } from '../common'
1
+ import { Amount, MPTAmount } from '../common'
2
2
 
3
3
  import {
4
4
  BaseTransaction,
@@ -27,7 +27,8 @@ export interface VaultWithdraw extends BaseTransaction {
27
27
  /**
28
28
  * The exact amount of Vault asset to withdraw.
29
29
  */
30
- Amount: Amount
30
+ // TODO: remove MPTAmount when MPTv2 is released
31
+ Amount: Amount | MPTAmount
31
32
 
32
33
  /**
33
34
  * An account to receive the assets. It must be able to receive the asset.