@hsuite/native-connect-angular 1.0.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 (276) hide show
  1. package/README.md +48 -0
  2. package/USAGE_EXAMPLES.md +476 -0
  3. package/assets/wallets/extension.svg +7 -0
  4. package/assets/wallets/hashpack.svg +6 -0
  5. package/assets/wallets/hsuite.svg +11 -0
  6. package/assets/wallets/kabila.svg +11 -0
  7. package/assets/wallets/walletconnect.svg +13 -0
  8. package/coverage/base.css +224 -0
  9. package/coverage/block-navigation.js +87 -0
  10. package/coverage/coverage-summary.json +50 -0
  11. package/coverage/favicon.png +0 -0
  12. package/coverage/index.html +476 -0
  13. package/coverage/lcov-report/base.css +224 -0
  14. package/coverage/lcov-report/block-navigation.js +87 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +476 -0
  17. package/coverage/lcov-report/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  18. package/coverage/lcov-report/lib/components/account-selector/account-actions/index.html +116 -0
  19. package/coverage/lcov-report/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  20. package/coverage/lcov-report/lib/components/account-selector/account-filter/index.html +116 -0
  21. package/coverage/lcov-report/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  22. package/coverage/lcov-report/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  23. package/coverage/lcov-report/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  24. package/coverage/lcov-report/lib/components/account-selector/account-list/index.html +116 -0
  25. package/coverage/lcov-report/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  26. package/coverage/lcov-report/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  27. package/coverage/lcov-report/lib/components/account-selector/index.html +161 -0
  28. package/coverage/lcov-report/lib/components/wallet-account-display/index.html +116 -0
  29. package/coverage/lcov-report/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  30. package/coverage/lcov-report/lib/components/wallet-connect-button/index.html +116 -0
  31. package/coverage/lcov-report/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  32. package/coverage/lcov-report/lib/components/wallet-connect-prompt/index.html +116 -0
  33. package/coverage/lcov-report/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  34. package/coverage/lcov-report/lib/components/wallet-connected-guard/index.html +116 -0
  35. package/coverage/lcov-report/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  36. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  37. package/coverage/lcov-report/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  38. package/coverage/lcov-report/lib/components/wallet-connection-modal/index.html +116 -0
  39. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  40. package/coverage/lcov-report/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  41. package/coverage/lcov-report/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  42. package/coverage/lcov-report/lib/components/wallet-session-display/index.html +116 -0
  43. package/coverage/lcov-report/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  44. package/coverage/lcov-report/lib/components/wallet-transaction-status/index.html +116 -0
  45. package/coverage/lcov-report/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  46. package/coverage/lcov-report/lib/directives/index.html +146 -0
  47. package/coverage/lcov-report/lib/directives/wallet-connected.directive.ts.html +670 -0
  48. package/coverage/lcov-report/lib/directives/wallet-context.directive.ts.html +547 -0
  49. package/coverage/lcov-report/lib/directives/wallet-events.directive.ts.html +781 -0
  50. package/coverage/lcov-report/lib/hsuite-wallet.module.ts.html +715 -0
  51. package/coverage/lcov-report/lib/index.html +116 -0
  52. package/coverage/lcov-report/lib/models/connection-config.model.ts.html +280 -0
  53. package/coverage/lcov-report/lib/models/index.html +131 -0
  54. package/coverage/lcov-report/lib/models/provider-types.ts.html +577 -0
  55. package/coverage/lcov-report/lib/providers/base-wallet-provider.ts.html +1138 -0
  56. package/coverage/lcov-report/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  57. package/coverage/lcov-report/lib/providers/hsuite-native/index.html +116 -0
  58. package/coverage/lcov-report/lib/providers/hsuite-native-provider.ts.html +2347 -0
  59. package/coverage/lcov-report/lib/providers/index.html +146 -0
  60. package/coverage/lcov-report/lib/providers/p2p-native/index.html +131 -0
  61. package/coverage/lcov-report/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  62. package/coverage/lcov-report/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  63. package/coverage/lcov-report/lib/providers/wallet-error-handler.ts.html +1132 -0
  64. package/coverage/lcov-report/lib/providers/walletconnect/core/index.html +176 -0
  65. package/coverage/lcov-report/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  66. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  67. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  68. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  69. package/coverage/lcov-report/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  70. package/coverage/lcov-report/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  71. package/coverage/lcov-report/lib/providers/walletconnect/signers/index.html +146 -0
  72. package/coverage/lcov-report/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  73. package/coverage/lcov-report/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  74. package/coverage/lcov-report/lib/services/index.html +191 -0
  75. package/coverage/lcov-report/lib/services/logger.service.ts.html +463 -0
  76. package/coverage/lcov-report/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  77. package/coverage/lcov-report/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  78. package/coverage/lcov-report/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  79. package/coverage/lcov-report/lib/services/transaction-builders/index.html +161 -0
  80. package/coverage/lcov-report/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  81. package/coverage/lcov-report/lib/services/transaction.service.ts.html +1123 -0
  82. package/coverage/lcov-report/lib/services/unified-wallet.service.ts.html +2641 -0
  83. package/coverage/lcov-report/lib/services/wallet-context.service.ts.html +637 -0
  84. package/coverage/lcov-report/lib/services/wallet-event-bus.service.ts.html +643 -0
  85. package/coverage/lcov-report/lib/services/wallet-providers.service.ts.html +496 -0
  86. package/coverage/lcov-report/lib/transports/chrome-extension-transport.ts.html +823 -0
  87. package/coverage/lcov-report/lib/transports/index.html +116 -0
  88. package/coverage/lcov-report/lib/utils/index.html +116 -0
  89. package/coverage/lcov-report/lib/utils/ledger-icons.util.ts.html +319 -0
  90. package/coverage/lcov-report/prettify.css +1 -0
  91. package/coverage/lcov-report/prettify.js +2 -0
  92. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  93. package/coverage/lcov-report/sorter.js +210 -0
  94. package/coverage/lcov.info +19252 -0
  95. package/coverage/lib/components/account-selector/account-actions/account-actions.component.ts.html +868 -0
  96. package/coverage/lib/components/account-selector/account-actions/index.html +116 -0
  97. package/coverage/lib/components/account-selector/account-filter/account-filter.component.ts.html +1288 -0
  98. package/coverage/lib/components/account-selector/account-filter/index.html +116 -0
  99. package/coverage/lib/components/account-selector/account-formatting.service.ts.html +685 -0
  100. package/coverage/lib/components/account-selector/account-grouping.service.ts.html +766 -0
  101. package/coverage/lib/components/account-selector/account-list/account-list.component.ts.html +1495 -0
  102. package/coverage/lib/components/account-selector/account-list/index.html +116 -0
  103. package/coverage/lib/components/account-selector/account-selector.component.ts.html +1495 -0
  104. package/coverage/lib/components/account-selector/account-selector.service.ts.html +1588 -0
  105. package/coverage/lib/components/account-selector/index.html +161 -0
  106. package/coverage/lib/components/wallet-account-display/index.html +116 -0
  107. package/coverage/lib/components/wallet-account-display/wallet-account-display.component.ts.html +505 -0
  108. package/coverage/lib/components/wallet-connect-button/index.html +116 -0
  109. package/coverage/lib/components/wallet-connect-button/wallet-connect-button.component.ts.html +805 -0
  110. package/coverage/lib/components/wallet-connect-prompt/index.html +116 -0
  111. package/coverage/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts.html +409 -0
  112. package/coverage/lib/components/wallet-connected-guard/index.html +116 -0
  113. package/coverage/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts.html +304 -0
  114. package/coverage/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts.html +436 -0
  115. package/coverage/lib/components/wallet-connection-modal/connection-method-step/index.html +116 -0
  116. package/coverage/lib/components/wallet-connection-modal/index.html +116 -0
  117. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/index.html +116 -0
  118. package/coverage/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts.html +2287 -0
  119. package/coverage/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts.html +2275 -0
  120. package/coverage/lib/components/wallet-session-display/index.html +116 -0
  121. package/coverage/lib/components/wallet-session-display/wallet-session-display.component.ts.html +676 -0
  122. package/coverage/lib/components/wallet-transaction-status/index.html +116 -0
  123. package/coverage/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts.html +703 -0
  124. package/coverage/lib/directives/index.html +146 -0
  125. package/coverage/lib/directives/wallet-connected.directive.ts.html +670 -0
  126. package/coverage/lib/directives/wallet-context.directive.ts.html +547 -0
  127. package/coverage/lib/directives/wallet-events.directive.ts.html +781 -0
  128. package/coverage/lib/hsuite-wallet.module.ts.html +715 -0
  129. package/coverage/lib/index.html +116 -0
  130. package/coverage/lib/models/connection-config.model.ts.html +280 -0
  131. package/coverage/lib/models/index.html +131 -0
  132. package/coverage/lib/models/provider-types.ts.html +577 -0
  133. package/coverage/lib/providers/base-wallet-provider.ts.html +1138 -0
  134. package/coverage/lib/providers/hsuite-native/channel-client.service.ts.html +2671 -0
  135. package/coverage/lib/providers/hsuite-native/index.html +116 -0
  136. package/coverage/lib/providers/hsuite-native-provider.ts.html +2347 -0
  137. package/coverage/lib/providers/index.html +146 -0
  138. package/coverage/lib/providers/p2p-native/index.html +131 -0
  139. package/coverage/lib/providers/p2p-native/p2p-native.provider.ts.html +2254 -0
  140. package/coverage/lib/providers/p2p-native/p2p-session-manager.ts.html +2170 -0
  141. package/coverage/lib/providers/wallet-error-handler.ts.html +1132 -0
  142. package/coverage/lib/providers/walletconnect/core/index.html +176 -0
  143. package/coverage/lib/providers/walletconnect/core/session-health.ts.html +673 -0
  144. package/coverage/lib/providers/walletconnect/core/walletconnect-client-manager.ts.html +1177 -0
  145. package/coverage/lib/providers/walletconnect/core/walletconnect-provider.ts.html +2563 -0
  146. package/coverage/lib/providers/walletconnect/core/walletconnect-session-store.ts.html +904 -0
  147. package/coverage/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts.html +982 -0
  148. package/coverage/lib/providers/walletconnect/signers/hedera-signer.ts.html +1915 -0
  149. package/coverage/lib/providers/walletconnect/signers/index.html +146 -0
  150. package/coverage/lib/providers/walletconnect/signers/signer-factory.ts.html +445 -0
  151. package/coverage/lib/providers/walletconnect/signers/xrpl-signer.ts.html +1519 -0
  152. package/coverage/lib/services/index.html +191 -0
  153. package/coverage/lib/services/logger.service.ts.html +463 -0
  154. package/coverage/lib/services/transaction-builders/base-transaction-builder.service.ts.html +1840 -0
  155. package/coverage/lib/services/transaction-builders/hedera-amount-utils.ts.html +337 -0
  156. package/coverage/lib/services/transaction-builders/hedera-transaction-builder.service.ts.html +3940 -0
  157. package/coverage/lib/services/transaction-builders/index.html +161 -0
  158. package/coverage/lib/services/transaction-builders/xrpl-transaction-builder.service.ts.html +2581 -0
  159. package/coverage/lib/services/transaction.service.ts.html +1123 -0
  160. package/coverage/lib/services/unified-wallet.service.ts.html +2641 -0
  161. package/coverage/lib/services/wallet-context.service.ts.html +637 -0
  162. package/coverage/lib/services/wallet-event-bus.service.ts.html +643 -0
  163. package/coverage/lib/services/wallet-providers.service.ts.html +496 -0
  164. package/coverage/lib/transports/chrome-extension-transport.ts.html +823 -0
  165. package/coverage/lib/transports/index.html +116 -0
  166. package/coverage/lib/utils/index.html +116 -0
  167. package/coverage/lib/utils/ledger-icons.util.ts.html +319 -0
  168. package/coverage/prettify.css +1 -0
  169. package/coverage/prettify.js +2 -0
  170. package/coverage/sort-arrow-sprite.png +0 -0
  171. package/coverage/sorter.js +210 -0
  172. package/dist/README.md +48 -0
  173. package/dist/fesm2022/hsuite-native-connect-angular.mjs +14592 -0
  174. package/dist/fesm2022/hsuite-native-connect-angular.mjs.map +1 -0
  175. package/dist/index.d.ts +6949 -0
  176. package/examples/minimal-connect.ts +178 -0
  177. package/examples/multi-protocol.ts +495 -0
  178. package/examples/transaction-signing.ts +361 -0
  179. package/jest.config.json +45 -0
  180. package/karma.conf.js +42 -0
  181. package/ng-package.json +20 -0
  182. package/package.json +60 -0
  183. package/src/index.ts +203 -0
  184. package/src/lib/components/account-selector/account-actions/account-actions.component.ts +261 -0
  185. package/src/lib/components/account-selector/account-filter/account-filter.component.ts +401 -0
  186. package/src/lib/components/account-selector/account-formatting.service.ts +200 -0
  187. package/src/lib/components/account-selector/account-grouping.service.ts +227 -0
  188. package/src/lib/components/account-selector/account-list/account-list.component.ts +470 -0
  189. package/src/lib/components/account-selector/account-selector.component.html +135 -0
  190. package/src/lib/components/account-selector/account-selector.component.scss +2039 -0
  191. package/src/lib/components/account-selector/account-selector.component.ts +470 -0
  192. package/src/lib/components/account-selector/account-selector.service.ts +501 -0
  193. package/src/lib/components/wallet-account-display/wallet-account-display.component.html +34 -0
  194. package/src/lib/components/wallet-account-display/wallet-account-display.component.scss +99 -0
  195. package/src/lib/components/wallet-account-display/wallet-account-display.component.ts +140 -0
  196. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.html +14 -0
  197. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.scss +272 -0
  198. package/src/lib/components/wallet-connect-button/wallet-connect-button.component.ts +240 -0
  199. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.html +24 -0
  200. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.scss +50 -0
  201. package/src/lib/components/wallet-connect-prompt/wallet-connect-prompt.component.ts +108 -0
  202. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.html +24 -0
  203. package/src/lib/components/wallet-connected-guard/wallet-connected-guard.component.ts +73 -0
  204. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.html +56 -0
  205. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.scss +218 -0
  206. package/src/lib/components/wallet-connection-modal/connection-method-step/connection-method-step.component.ts +117 -0
  207. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.html +94 -0
  208. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.scss +272 -0
  209. package/src/lib/components/wallet-connection-modal/qr-pairing-step/qr-pairing-step.component.ts +734 -0
  210. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.html +197 -0
  211. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.scss +678 -0
  212. package/src/lib/components/wallet-connection-modal/wallet-connection-modal.component.ts +730 -0
  213. package/src/lib/components/wallet-session-display/wallet-session-display.component.html +110 -0
  214. package/src/lib/components/wallet-session-display/wallet-session-display.component.scss +179 -0
  215. package/src/lib/components/wallet-session-display/wallet-session-display.component.ts +197 -0
  216. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.html +65 -0
  217. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.scss +254 -0
  218. package/src/lib/components/wallet-transaction-status/wallet-transaction-status.component.ts +206 -0
  219. package/src/lib/directives/wallet-connected.directive.ts +195 -0
  220. package/src/lib/directives/wallet-context.directive.ts +154 -0
  221. package/src/lib/directives/wallet-events.directive.ts +232 -0
  222. package/src/lib/hsuite-wallet.module.ts +210 -0
  223. package/src/lib/models/connection-config.model.ts +65 -0
  224. package/src/lib/models/provider-types.ts +164 -0
  225. package/src/lib/models/unified-account.model.ts +76 -0
  226. package/src/lib/models/wallet-context.model.ts +121 -0
  227. package/src/lib/models/wallet-events.model.ts +158 -0
  228. package/src/lib/providers/base-wallet-provider.ts +351 -0
  229. package/src/lib/providers/hsuite-native/channel-client.service.spec.ts +73 -0
  230. package/src/lib/providers/hsuite-native/channel-client.service.ts +862 -0
  231. package/src/lib/providers/hsuite-native/index.ts +8 -0
  232. package/src/lib/providers/hsuite-native-provider.ts +754 -0
  233. package/src/lib/providers/mobile-native/mobile-native.provider.spec.ts +19 -0
  234. package/src/lib/providers/p2p-native/index.ts +30 -0
  235. package/src/lib/providers/p2p-native/p2p-native.provider.spec.ts +523 -0
  236. package/src/lib/providers/p2p-native/p2p-native.provider.ts +723 -0
  237. package/src/lib/providers/p2p-native/p2p-session-manager.ts +695 -0
  238. package/src/lib/providers/wallet-error-handler.ts +349 -0
  239. package/src/lib/providers/walletconnect/core/base-signer.interface.ts +122 -0
  240. package/src/lib/providers/walletconnect/core/session-health.ts +196 -0
  241. package/src/lib/providers/walletconnect/core/walletconnect-client-manager.ts +364 -0
  242. package/src/lib/providers/walletconnect/core/walletconnect-provider.integration.spec.ts +348 -0
  243. package/src/lib/providers/walletconnect/core/walletconnect-provider.ts +826 -0
  244. package/src/lib/providers/walletconnect/core/walletconnect-session-store.ts +273 -0
  245. package/src/lib/providers/walletconnect/core/walletconnect-signing-orchestrator.ts +299 -0
  246. package/src/lib/providers/walletconnect/core/walletconnect-types.ts +48 -0
  247. package/src/lib/providers/walletconnect/index.ts +33 -0
  248. package/src/lib/providers/walletconnect/signers/hedera-signer.spec.ts +367 -0
  249. package/src/lib/providers/walletconnect/signers/hedera-signer.ts +610 -0
  250. package/src/lib/providers/walletconnect/signers/signer-factory.spec.ts +62 -0
  251. package/src/lib/providers/walletconnect/signers/signer-factory.ts +120 -0
  252. package/src/lib/providers/walletconnect/signers/xrpl-signer.spec.ts +296 -0
  253. package/src/lib/providers/walletconnect/signers/xrpl-signer.ts +478 -0
  254. package/src/lib/services/logger.service.ts +126 -0
  255. package/src/lib/services/transaction-builders/base-transaction-builder.service.ts +585 -0
  256. package/src/lib/services/transaction-builders/hedera-amount-utils.ts +84 -0
  257. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.spec.ts +741 -0
  258. package/src/lib/services/transaction-builders/hedera-transaction-builder.service.ts +1285 -0
  259. package/src/lib/services/transaction-builders/index.ts +54 -0
  260. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.spec.ts +937 -0
  261. package/src/lib/services/transaction-builders/xrpl-transaction-builder.service.ts +832 -0
  262. package/src/lib/services/transaction.service.ts +346 -0
  263. package/src/lib/services/unified-wallet.service.spec.ts +1382 -0
  264. package/src/lib/services/unified-wallet.service.ts +852 -0
  265. package/src/lib/services/wallet-context.service.ts +184 -0
  266. package/src/lib/services/wallet-event-bus.service.ts +186 -0
  267. package/src/lib/services/wallet-providers.service.ts +137 -0
  268. package/src/lib/transports/chrome-extension-transport.ts +246 -0
  269. package/src/lib/utils/index.ts +14 -0
  270. package/src/lib/utils/ledger-icons.util.ts +78 -0
  271. package/test/test-setup.ts +21 -0
  272. package/test-setup.ts +63 -0
  273. package/tsconfig.build.json +11 -0
  274. package/tsconfig.json +29 -0
  275. package/tsconfig.spec.json +15 -0
  276. package/vitest.config.ts +48 -0
@@ -0,0 +1,937 @@
1
+ /**
2
+ * @fileoverview Unit tests for XrplTransactionBuilderService
3
+ *
4
+ * Tests cover:
5
+ * - Payment transactions (XRP and tokens)
6
+ * - TrustSet transactions
7
+ * - Offer/DEX transactions (create, cancel)
8
+ * - AccountSet transactions
9
+ * - Escrow transactions (create, finish, cancel)
10
+ * - Payment channel transactions
11
+ * - Check transactions (create, cash, cancel)
12
+ * - DepositPreauth transactions
13
+ * - SignerListSet transactions
14
+ * - TicketCreate transactions
15
+ * - NFT transactions (mint, burn, create/accept/cancel offers)
16
+ * - Batch transactions
17
+ * - Error handling
18
+ *
19
+ * @module services/transaction-builders/xrpl-transaction-builder
20
+ * @since 2.0.0
21
+ */
22
+
23
+ import { TestBed } from '@angular/core/testing';
24
+ import { describe, it, expect, beforeEach } from 'vitest';
25
+ import { XrplTransactionBuilderService } from './xrpl-transaction-builder.service';
26
+
27
+ describe('XrplTransactionBuilderService', () => {
28
+ let service: XrplTransactionBuilderService;
29
+
30
+ const mockAccount = 'rAccountSourceXXXXXXXXXXXXXX';
31
+ const mockDestination = 'rAccountDestXXXXXXXXXXXXXXX';
32
+ const mockIssuer = 'rIssuerAccountXXXXXXXXXXXXXX';
33
+
34
+ beforeEach(async () => {
35
+ await TestBed.configureTestingModule({
36
+ providers: [XrplTransactionBuilderService],
37
+ }).compileComponents();
38
+
39
+ service = TestBed.inject(XrplTransactionBuilderService);
40
+ });
41
+
42
+ it('should create', () => {
43
+ expect(service).toBeTruthy();
44
+ });
45
+
46
+ /**
47
+ * Helper to decode and parse base64 transaction
48
+ */
49
+ function decodeTransaction(base64: string): Record<string, unknown> {
50
+ const json = atob(base64);
51
+ return JSON.parse(json);
52
+ }
53
+
54
+ // ==================== PAYMENT TRANSACTIONS ====================
55
+ describe('buildPayment', () => {
56
+ it('should build XRP payment transaction', async () => {
57
+ const amount = '1000000'; // 1 XRP in drops
58
+ const result = await service.buildPayment(mockAccount, mockDestination, amount);
59
+
60
+ expect(result).toBeDefined();
61
+ expect(typeof result).toBe('string');
62
+
63
+ const tx = decodeTransaction(result);
64
+ expect(tx.TransactionType).toBe('Payment');
65
+ expect(tx.Account).toBe(mockAccount);
66
+ expect(tx.Destination).toBe(mockDestination);
67
+ expect(tx.Amount).toBe(amount);
68
+ });
69
+
70
+ it('should build token payment transaction', async () => {
71
+ const amount = '100';
72
+ const currency = 'USD';
73
+
74
+ const result = await service.buildPayment(
75
+ mockAccount,
76
+ mockDestination,
77
+ amount,
78
+ true,
79
+ currency,
80
+ mockIssuer
81
+ );
82
+
83
+ const tx = decodeTransaction(result);
84
+ expect(tx.TransactionType).toBe('Payment');
85
+ expect(tx.Account).toBe(mockAccount);
86
+ expect(tx.Destination).toBe(mockDestination);
87
+ expect(tx.Amount).toEqual({
88
+ currency,
89
+ issuer: mockIssuer,
90
+ value: amount,
91
+ });
92
+ });
93
+
94
+ it('should default to XRP payment when isToken is false', async () => {
95
+ const amount = '5000000';
96
+ const result = await service.buildPayment(mockAccount, mockDestination, amount, false);
97
+
98
+ const tx = decodeTransaction(result);
99
+ expect(tx.Amount).toBe(amount);
100
+ });
101
+
102
+ it('should treat as XRP payment when isToken is true but no currency/issuer provided', async () => {
103
+ const amount = '5000000';
104
+ const result = await service.buildPayment(mockAccount, mockDestination, amount, true);
105
+
106
+ const tx = decodeTransaction(result);
107
+ // When isToken is true but currency/issuer are missing, it falls back to XRP
108
+ expect(tx.Amount).toBe(amount);
109
+ });
110
+ });
111
+
112
+ // ==================== TRUSTSET TRANSACTIONS ====================
113
+ describe('buildTrustSet', () => {
114
+ it('should build TrustSet transaction', async () => {
115
+ const currency = 'USD';
116
+ const limit = '1000000';
117
+
118
+ const result = await service.buildTrustSet(mockAccount, currency, mockIssuer, limit);
119
+
120
+ const tx = decodeTransaction(result);
121
+ expect(tx.TransactionType).toBe('TrustSet');
122
+ expect(tx.Account).toBe(mockAccount);
123
+ expect(tx.LimitAmount).toEqual({
124
+ currency,
125
+ issuer: mockIssuer,
126
+ value: limit,
127
+ });
128
+ });
129
+
130
+ it('should handle different currency codes', async () => {
131
+ const currencies = ['EUR', 'GBP', 'JPY', 'BTC'];
132
+
133
+ for (const currency of currencies) {
134
+ const result = await service.buildTrustSet(mockAccount, currency, mockIssuer, '100000');
135
+ const tx = decodeTransaction(result);
136
+ expect(tx.LimitAmount).toHaveProperty('currency', currency);
137
+ }
138
+ });
139
+ });
140
+
141
+ // ==================== OFFER TRANSACTIONS ====================
142
+ describe('buildOfferCreate', () => {
143
+ it('should build OfferCreate with XRP amounts', async () => {
144
+ const takerPays = '1000000';
145
+ const takerGets = '500000';
146
+
147
+ const result = await service.buildOfferCreate(mockAccount, takerPays, takerGets);
148
+
149
+ const tx = decodeTransaction(result);
150
+ expect(tx.TransactionType).toBe('OfferCreate');
151
+ expect(tx.Account).toBe(mockAccount);
152
+ expect(tx.TakerPays).toBe(takerPays);
153
+ expect(tx.TakerGets).toBe(takerGets);
154
+ });
155
+
156
+ it('should build OfferCreate with token amounts', async () => {
157
+ const takerPays = { currency: 'USD', issuer: mockIssuer, value: '100' };
158
+ const takerGets = { currency: 'EUR', issuer: mockIssuer, value: '85' };
159
+
160
+ const result = await service.buildOfferCreate(mockAccount, takerPays, takerGets);
161
+
162
+ const tx = decodeTransaction(result);
163
+ expect(tx.TakerPays).toEqual(takerPays);
164
+ expect(tx.TakerGets).toEqual(takerGets);
165
+ });
166
+
167
+ it('should build OfferCreate with mixed XRP/token amounts', async () => {
168
+ const takerPays = '1000000'; // XRP
169
+ const takerGets = { currency: 'USD', issuer: mockIssuer, value: '100' };
170
+
171
+ const result = await service.buildOfferCreate(mockAccount, takerPays, takerGets);
172
+
173
+ const tx = decodeTransaction(result);
174
+ expect(tx.TakerPays).toBe(takerPays);
175
+ expect(tx.TakerGets).toEqual(takerGets);
176
+ });
177
+ });
178
+
179
+ describe('buildOfferCancel', () => {
180
+ it('should build OfferCancel transaction', async () => {
181
+ const offerSequence = 12345;
182
+
183
+ const result = await service.buildOfferCancel(mockAccount, offerSequence);
184
+
185
+ const tx = decodeTransaction(result);
186
+ expect(tx.TransactionType).toBe('OfferCancel');
187
+ expect(tx.Account).toBe(mockAccount);
188
+ expect(tx.OfferSequence).toBe(offerSequence);
189
+ });
190
+ });
191
+
192
+ // ==================== ACCOUNTSET TRANSACTIONS ====================
193
+ describe('buildAccountSet', () => {
194
+ it('should build AccountSet with domain', async () => {
195
+ const domain = '6578616D706C652E636F6D'; // example.com in hex
196
+
197
+ const result = await service.buildAccountSet(mockAccount, { domain });
198
+
199
+ const tx = decodeTransaction(result);
200
+ expect(tx.TransactionType).toBe('AccountSet');
201
+ expect(tx.Account).toBe(mockAccount);
202
+ expect(tx.domain).toBe(domain);
203
+ });
204
+
205
+ it('should build AccountSet with multiple options', async () => {
206
+ const options = {
207
+ domain: '6578616D706C652E636F6D',
208
+ emailHash: 'abcd1234',
209
+ transferRate: 1005000000,
210
+ tickSize: 5,
211
+ setFlag: 8,
212
+ };
213
+
214
+ const result = await service.buildAccountSet(mockAccount, options);
215
+
216
+ const tx = decodeTransaction(result);
217
+ expect(tx.domain).toBe(options.domain);
218
+ expect(tx.emailHash).toBe(options.emailHash);
219
+ expect(tx.transferRate).toBe(options.transferRate);
220
+ expect(tx.tickSize).toBe(options.tickSize);
221
+ expect(tx.setFlag).toBe(options.setFlag);
222
+ });
223
+
224
+ it('should build AccountSet with clearFlag', async () => {
225
+ const result = await service.buildAccountSet(mockAccount, { clearFlag: 8 });
226
+
227
+ const tx = decodeTransaction(result);
228
+ expect(tx.clearFlag).toBe(8);
229
+ });
230
+
231
+ it('should build AccountSet with empty options', async () => {
232
+ const result = await service.buildAccountSet(mockAccount, {});
233
+
234
+ const tx = decodeTransaction(result);
235
+ expect(tx.TransactionType).toBe('AccountSet');
236
+ expect(tx.Account).toBe(mockAccount);
237
+ });
238
+ });
239
+
240
+ // ==================== ESCROW TRANSACTIONS ====================
241
+ describe('buildEscrowCreate', () => {
242
+ it('should build EscrowCreate without cancelAfter', async () => {
243
+ const amount = '1000000';
244
+ const finishAfter = 1700000000;
245
+
246
+ const result = await service.buildEscrowCreate(
247
+ mockAccount,
248
+ mockDestination,
249
+ amount,
250
+ finishAfter
251
+ );
252
+
253
+ const tx = decodeTransaction(result);
254
+ expect(tx.TransactionType).toBe('EscrowCreate');
255
+ expect(tx.Account).toBe(mockAccount);
256
+ expect(tx.Destination).toBe(mockDestination);
257
+ expect(tx.Amount).toBe(amount);
258
+ expect(tx.FinishAfter).toBe(finishAfter);
259
+ expect(tx.CancelAfter).toBeUndefined();
260
+ });
261
+
262
+ it('should build EscrowCreate with cancelAfter', async () => {
263
+ const amount = '1000000';
264
+ const finishAfter = 1700000000;
265
+ const cancelAfter = 1800000000;
266
+
267
+ const result = await service.buildEscrowCreate(
268
+ mockAccount,
269
+ mockDestination,
270
+ amount,
271
+ finishAfter,
272
+ cancelAfter
273
+ );
274
+
275
+ const tx = decodeTransaction(result);
276
+ expect(tx.FinishAfter).toBe(finishAfter);
277
+ expect(tx.CancelAfter).toBe(cancelAfter);
278
+ });
279
+ });
280
+
281
+ describe('buildEscrowFinish', () => {
282
+ it('should build EscrowFinish transaction', async () => {
283
+ const owner = 'rOwnerAccountXXXXXXXXXXXXXXX';
284
+ const offerSequence = 54321;
285
+
286
+ const result = await service.buildEscrowFinish(mockAccount, owner, offerSequence);
287
+
288
+ const tx = decodeTransaction(result);
289
+ expect(tx.TransactionType).toBe('EscrowFinish');
290
+ expect(tx.Account).toBe(mockAccount);
291
+ expect(tx.Owner).toBe(owner);
292
+ expect(tx.OfferSequence).toBe(offerSequence);
293
+ });
294
+ });
295
+
296
+ describe('buildEscrowCancel', () => {
297
+ it('should build EscrowCancel transaction', async () => {
298
+ const owner = 'rOwnerAccountXXXXXXXXXXXXXXX';
299
+ const offerSequence = 54321;
300
+
301
+ const result = await service.buildEscrowCancel(mockAccount, owner, offerSequence);
302
+
303
+ const tx = decodeTransaction(result);
304
+ expect(tx.TransactionType).toBe('EscrowCancel');
305
+ expect(tx.Account).toBe(mockAccount);
306
+ expect(tx.Owner).toBe(owner);
307
+ expect(tx.OfferSequence).toBe(offerSequence);
308
+ });
309
+ });
310
+
311
+ // ==================== PAYMENT CHANNEL TRANSACTIONS ====================
312
+ describe('buildPaymentChannelCreate', () => {
313
+ it('should build PaymentChannelCreate transaction', async () => {
314
+ const amount = '10000000';
315
+ const settleDelay = 86400;
316
+ const publicKey = '03abcdef1234567890';
317
+
318
+ const result = await service.buildPaymentChannelCreate(
319
+ mockAccount,
320
+ mockDestination,
321
+ amount,
322
+ settleDelay,
323
+ publicKey
324
+ );
325
+
326
+ const tx = decodeTransaction(result);
327
+ expect(tx.TransactionType).toBe('PaymentChannelCreate');
328
+ expect(tx.Account).toBe(mockAccount);
329
+ expect(tx.Destination).toBe(mockDestination);
330
+ expect(tx.Amount).toBe(amount);
331
+ expect(tx.SettleDelay).toBe(settleDelay);
332
+ expect(tx.PublicKey).toBe(publicKey);
333
+ });
334
+ });
335
+
336
+ describe('buildPaymentChannelFund', () => {
337
+ it('should build PaymentChannelFund transaction', async () => {
338
+ const channel = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
339
+ const amount = '5000000';
340
+
341
+ const result = await service.buildPaymentChannelFund(mockAccount, channel, amount);
342
+
343
+ const tx = decodeTransaction(result);
344
+ expect(tx.TransactionType).toBe('PaymentChannelFund');
345
+ expect(tx.Account).toBe(mockAccount);
346
+ expect(tx.Channel).toBe(channel);
347
+ expect(tx.Amount).toBe(amount);
348
+ });
349
+ });
350
+
351
+ describe('buildPaymentChannelClaim', () => {
352
+ it('should build PaymentChannelClaim with amount', async () => {
353
+ const channel = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
354
+ const amount = '1000000';
355
+
356
+ const result = await service.buildPaymentChannelClaim(mockAccount, channel, amount);
357
+
358
+ const tx = decodeTransaction(result);
359
+ expect(tx.TransactionType).toBe('PaymentChannelClaim');
360
+ expect(tx.Account).toBe(mockAccount);
361
+ expect(tx.Channel).toBe(channel);
362
+ expect(tx.Amount).toBe(amount);
363
+ });
364
+
365
+ it('should build PaymentChannelClaim without amount', async () => {
366
+ const channel = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
367
+
368
+ const result = await service.buildPaymentChannelClaim(mockAccount, channel);
369
+
370
+ const tx = decodeTransaction(result);
371
+ expect(tx.TransactionType).toBe('PaymentChannelClaim');
372
+ expect(tx.Channel).toBe(channel);
373
+ expect(tx.Amount).toBeUndefined();
374
+ });
375
+ });
376
+
377
+ // ==================== CHECK TRANSACTIONS ====================
378
+ describe('buildCheckCreate', () => {
379
+ it('should build CheckCreate transaction', async () => {
380
+ const sendMax = '5000000';
381
+
382
+ const result = await service.buildCheckCreate(mockAccount, mockDestination, sendMax);
383
+
384
+ const tx = decodeTransaction(result);
385
+ expect(tx.TransactionType).toBe('CheckCreate');
386
+ expect(tx.Account).toBe(mockAccount);
387
+ expect(tx.Destination).toBe(mockDestination);
388
+ expect(tx.SendMax).toBe(sendMax);
389
+ });
390
+ });
391
+
392
+ describe('buildCheckCash', () => {
393
+ it('should build CheckCash with amount', async () => {
394
+ const checkID = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
395
+ const amount = '4000000';
396
+
397
+ const result = await service.buildCheckCash(mockAccount, checkID, amount);
398
+
399
+ const tx = decodeTransaction(result);
400
+ expect(tx.TransactionType).toBe('CheckCash');
401
+ expect(tx.Account).toBe(mockAccount);
402
+ expect(tx.CheckID).toBe(checkID);
403
+ expect(tx.Amount).toBe(amount);
404
+ expect(tx.DeliverMin).toBeUndefined();
405
+ });
406
+
407
+ it('should build CheckCash with deliverMin', async () => {
408
+ const checkID = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
409
+ const deliverMin = '3500000';
410
+
411
+ const result = await service.buildCheckCash(mockAccount, checkID, undefined, deliverMin);
412
+
413
+ const tx = decodeTransaction(result);
414
+ expect(tx.Amount).toBeUndefined();
415
+ expect(tx.DeliverMin).toBe(deliverMin);
416
+ });
417
+
418
+ it('should build CheckCash with both amount and deliverMin', async () => {
419
+ const checkID = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
420
+ const amount = '4000000';
421
+ const deliverMin = '3500000';
422
+
423
+ const result = await service.buildCheckCash(mockAccount, checkID, amount, deliverMin);
424
+
425
+ const tx = decodeTransaction(result);
426
+ expect(tx.Amount).toBe(amount);
427
+ expect(tx.DeliverMin).toBe(deliverMin);
428
+ });
429
+
430
+ it('should build CheckCash with neither amount nor deliverMin', async () => {
431
+ const checkID = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
432
+
433
+ const result = await service.buildCheckCash(mockAccount, checkID);
434
+
435
+ const tx = decodeTransaction(result);
436
+ expect(tx.CheckID).toBe(checkID);
437
+ expect(tx.Amount).toBeUndefined();
438
+ expect(tx.DeliverMin).toBeUndefined();
439
+ });
440
+ });
441
+
442
+ describe('buildCheckCancel', () => {
443
+ it('should build CheckCancel transaction', async () => {
444
+ const checkID = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
445
+
446
+ const result = await service.buildCheckCancel(mockAccount, checkID);
447
+
448
+ const tx = decodeTransaction(result);
449
+ expect(tx.TransactionType).toBe('CheckCancel');
450
+ expect(tx.Account).toBe(mockAccount);
451
+ expect(tx.CheckID).toBe(checkID);
452
+ });
453
+ });
454
+
455
+ // ==================== DEPOSITPREAUTH TRANSACTIONS ====================
456
+ describe('buildDepositPreauth', () => {
457
+ it('should build DepositPreauth with authorize', async () => {
458
+ const authorize = 'rAuthorizeAccountXXXXXXXXXXX';
459
+
460
+ const result = await service.buildDepositPreauth(mockAccount, authorize);
461
+
462
+ const tx = decodeTransaction(result);
463
+ expect(tx.TransactionType).toBe('DepositPreauth');
464
+ expect(tx.Account).toBe(mockAccount);
465
+ expect(tx.Authorize).toBe(authorize);
466
+ expect(tx.Unauthorize).toBeUndefined();
467
+ });
468
+
469
+ it('should build DepositPreauth with unauthorize', async () => {
470
+ const unauthorize = 'rUnauthorizeAccountXXXXXXXXX';
471
+
472
+ const result = await service.buildDepositPreauth(mockAccount, undefined, unauthorize);
473
+
474
+ const tx = decodeTransaction(result);
475
+ expect(tx.Authorize).toBeUndefined();
476
+ expect(tx.Unauthorize).toBe(unauthorize);
477
+ });
478
+
479
+ it('should build DepositPreauth with neither authorize nor unauthorize', async () => {
480
+ const result = await service.buildDepositPreauth(mockAccount);
481
+
482
+ const tx = decodeTransaction(result);
483
+ expect(tx.TransactionType).toBe('DepositPreauth');
484
+ expect(tx.Account).toBe(mockAccount);
485
+ });
486
+ });
487
+
488
+ // ==================== SIGNERLISTSET TRANSACTIONS ====================
489
+ describe('buildSignerListSet', () => {
490
+ it('should build SignerListSet transaction', async () => {
491
+ const signerQuorum = 2;
492
+ const signerEntries = [
493
+ { account: 'rSigner1XXXXXXXXXXXXXXXXXX', weight: 1 },
494
+ { account: 'rSigner2XXXXXXXXXXXXXXXXXX', weight: 1 },
495
+ { account: 'rSigner3XXXXXXXXXXXXXXXXXX', weight: 1 },
496
+ ];
497
+
498
+ const result = await service.buildSignerListSet(mockAccount, signerQuorum, signerEntries);
499
+
500
+ const tx = decodeTransaction(result);
501
+ expect(tx.TransactionType).toBe('SignerListSet');
502
+ expect(tx.Account).toBe(mockAccount);
503
+ expect(tx.SignerQuorum).toBe(signerQuorum);
504
+ expect(tx.SignerEntries).toEqual([
505
+ { SignerEntry: { Account: 'rSigner1XXXXXXXXXXXXXXXXXX', SignerWeight: 1 } },
506
+ { SignerEntry: { Account: 'rSigner2XXXXXXXXXXXXXXXXXX', SignerWeight: 1 } },
507
+ { SignerEntry: { Account: 'rSigner3XXXXXXXXXXXXXXXXXX', SignerWeight: 1 } },
508
+ ]);
509
+ });
510
+
511
+ it('should build SignerListSet with different weights', async () => {
512
+ const signerQuorum = 3;
513
+ const signerEntries = [
514
+ { account: 'rSigner1XXXXXXXXXXXXXXXXXX', weight: 2 },
515
+ { account: 'rSigner2XXXXXXXXXXXXXXXXXX', weight: 1 },
516
+ ];
517
+
518
+ const result = await service.buildSignerListSet(mockAccount, signerQuorum, signerEntries);
519
+
520
+ const tx = decodeTransaction(result);
521
+ expect(tx.SignerQuorum).toBe(3);
522
+ expect(tx.SignerEntries).toHaveLength(2);
523
+ });
524
+
525
+ it('should build SignerListSet with empty signer list (disable multisig)', async () => {
526
+ const result = await service.buildSignerListSet(mockAccount, 0, []);
527
+
528
+ const tx = decodeTransaction(result);
529
+ expect(tx.SignerQuorum).toBe(0);
530
+ expect(tx.SignerEntries).toEqual([]);
531
+ });
532
+ });
533
+
534
+ // ==================== TICKETCREATE TRANSACTIONS ====================
535
+ describe('buildTicketCreate', () => {
536
+ it('should build TicketCreate transaction', async () => {
537
+ const ticketCount = 10;
538
+
539
+ const result = await service.buildTicketCreate(mockAccount, ticketCount);
540
+
541
+ const tx = decodeTransaction(result);
542
+ expect(tx.TransactionType).toBe('TicketCreate');
543
+ expect(tx.Account).toBe(mockAccount);
544
+ expect(tx.TicketCount).toBe(ticketCount);
545
+ });
546
+
547
+ it('should build TicketCreate with minimum ticket count', async () => {
548
+ const result = await service.buildTicketCreate(mockAccount, 1);
549
+
550
+ const tx = decodeTransaction(result);
551
+ expect(tx.TicketCount).toBe(1);
552
+ });
553
+
554
+ it('should build TicketCreate with maximum ticket count', async () => {
555
+ const result = await service.buildTicketCreate(mockAccount, 250);
556
+
557
+ const tx = decodeTransaction(result);
558
+ expect(tx.TicketCount).toBe(250);
559
+ });
560
+ });
561
+
562
+ // ==================== NFT TRANSACTIONS ====================
563
+ describe('buildNFTMint', () => {
564
+ it('should build NFTokenMint transaction', async () => {
565
+ const uri = '697066733A2F2F6261666B7265696768'; // ipfs://... in hex
566
+ const flags = 8; // tfTransferable
567
+ const transferFee = 500; // 5% in basis points
568
+ const taxon = 0;
569
+
570
+ const result = await service.buildNFTMint(mockAccount, uri, flags, transferFee, taxon);
571
+
572
+ const tx = decodeTransaction(result);
573
+ expect(tx.TransactionType).toBe('NFTokenMint');
574
+ expect(tx.Account).toBe(mockAccount);
575
+ expect(tx.URI).toBe(uri);
576
+ expect(tx.Flags).toBe(flags);
577
+ expect(tx.TransferFee).toBe(transferFee);
578
+ expect(tx.NFTokenTaxon).toBe(taxon);
579
+ });
580
+
581
+ it('should build NFTokenMint with different taxons', async () => {
582
+ const taxons = [0, 1, 100, 999999];
583
+
584
+ for (const taxon of taxons) {
585
+ const result = await service.buildNFTMint(mockAccount, 'abc', 0, 0, taxon);
586
+ const tx = decodeTransaction(result);
587
+ expect(tx.NFTokenTaxon).toBe(taxon);
588
+ }
589
+ });
590
+ });
591
+
592
+ describe('buildNFTBurn', () => {
593
+ it('should build NFTokenBurn transaction', async () => {
594
+ const nftokenID = '000800006203F49C21D5D6E022CB16DE3538F248662FC73C00000000000001E2';
595
+
596
+ const result = await service.buildNFTBurn(mockAccount, nftokenID);
597
+
598
+ const tx = decodeTransaction(result);
599
+ expect(tx.TransactionType).toBe('NFTokenBurn');
600
+ expect(tx.Account).toBe(mockAccount);
601
+ expect(tx.NFTokenID).toBe(nftokenID);
602
+ });
603
+ });
604
+
605
+ describe('buildNFTCreateOffer', () => {
606
+ it('should build NFTokenCreateOffer for sell', async () => {
607
+ const nftokenID = '000800006203F49C21D5D6E022CB16DE3538F248662FC73C00000000000001E2';
608
+ const amount = '1000000';
609
+ const flags = 1; // tfSellNFToken
610
+
611
+ const result = await service.buildNFTCreateOffer(mockAccount, nftokenID, amount, flags);
612
+
613
+ const tx = decodeTransaction(result);
614
+ expect(tx.TransactionType).toBe('NFTokenCreateOffer');
615
+ expect(tx.Account).toBe(mockAccount);
616
+ expect(tx.NFTokenID).toBe(nftokenID);
617
+ expect(tx.Amount).toBe(amount);
618
+ expect(tx.Flags).toBe(flags);
619
+ expect(tx.Destination).toBeUndefined();
620
+ });
621
+
622
+ it('should build NFTokenCreateOffer for buy', async () => {
623
+ const nftokenID = '000800006203F49C21D5D6E022CB16DE3538F248662FC73C00000000000001E2';
624
+ const amount = '500000';
625
+ const flags = 0; // Buy offer
626
+
627
+ const result = await service.buildNFTCreateOffer(mockAccount, nftokenID, amount, flags);
628
+
629
+ const tx = decodeTransaction(result);
630
+ expect(tx.Flags).toBe(0);
631
+ });
632
+
633
+ it('should build NFTokenCreateOffer with destination', async () => {
634
+ const nftokenID = '000800006203F49C21D5D6E022CB16DE3538F248662FC73C00000000000001E2';
635
+ const amount = '1000000';
636
+ const flags = 1;
637
+
638
+ const result = await service.buildNFTCreateOffer(
639
+ mockAccount,
640
+ nftokenID,
641
+ amount,
642
+ flags,
643
+ mockDestination
644
+ );
645
+
646
+ const tx = decodeTransaction(result);
647
+ expect(tx.Destination).toBe(mockDestination);
648
+ });
649
+ });
650
+
651
+ describe('buildNFTAcceptOffer', () => {
652
+ it('should build NFTokenAcceptOffer with sell offer', async () => {
653
+ const sellOffer = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
654
+
655
+ const result = await service.buildNFTAcceptOffer(mockAccount, sellOffer);
656
+
657
+ const tx = decodeTransaction(result);
658
+ expect(tx.TransactionType).toBe('NFTokenAcceptOffer');
659
+ expect(tx.Account).toBe(mockAccount);
660
+ expect(tx.NFTokenSellOffer).toBe(sellOffer);
661
+ expect(tx.NFTokenBuyOffer).toBeUndefined();
662
+ });
663
+
664
+ it('should build NFTokenAcceptOffer with buy offer', async () => {
665
+ const buyOffer = 'D2BF7EEEFC16CF3089D1BAE7FF413059E0644802EC859EDEE4C96A03089D1BAE';
666
+
667
+ const result = await service.buildNFTAcceptOffer(mockAccount, undefined, buyOffer);
668
+
669
+ const tx = decodeTransaction(result);
670
+ expect(tx.NFTokenSellOffer).toBeUndefined();
671
+ expect(tx.NFTokenBuyOffer).toBe(buyOffer);
672
+ });
673
+
674
+ it('should build NFTokenAcceptOffer with both offers (brokered mode)', async () => {
675
+ const sellOffer = 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA';
676
+ const buyOffer = 'D2BF7EEEFC16CF3089D1BAE7FF413059E0644802EC859EDEE4C96A03089D1BAE';
677
+
678
+ const result = await service.buildNFTAcceptOffer(mockAccount, sellOffer, buyOffer);
679
+
680
+ const tx = decodeTransaction(result);
681
+ expect(tx.NFTokenSellOffer).toBe(sellOffer);
682
+ expect(tx.NFTokenBuyOffer).toBe(buyOffer);
683
+ });
684
+ });
685
+
686
+ describe('buildNFTCancelOffer', () => {
687
+ it('should build NFTokenCancelOffer with single offer', async () => {
688
+ const offers = ['C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA'];
689
+
690
+ const result = await service.buildNFTCancelOffer(mockAccount, offers);
691
+
692
+ const tx = decodeTransaction(result);
693
+ expect(tx.TransactionType).toBe('NFTokenCancelOffer');
694
+ expect(tx.Account).toBe(mockAccount);
695
+ expect(tx.NFTokenOffers).toEqual(offers);
696
+ });
697
+
698
+ it('should build NFTokenCancelOffer with multiple offers', async () => {
699
+ const offers = [
700
+ 'C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B95992978C0BA',
701
+ 'D2BF7EEEFC16CF3089D1BAE7FF413059E0644802EC859EDEE4C96A03089D1BAE',
702
+ 'E3CG8FFFGD27DG4190E2CBF8GG524160F1755913FD960FEEF5D97B14190E2CBF',
703
+ ];
704
+
705
+ const result = await service.buildNFTCancelOffer(mockAccount, offers);
706
+
707
+ const tx = decodeTransaction(result);
708
+ expect(tx.NFTokenOffers).toHaveLength(3);
709
+ });
710
+ });
711
+
712
+ // ==================== BATCH TRANSACTIONS ====================
713
+ describe('buildBatchTransaction', () => {
714
+ const tfAllOrNothing = 65536;
715
+ const tfInnerBatchTxn = 1073741824;
716
+
717
+ it('should build batch with payment transactions', async () => {
718
+ const innerTransactions = [
719
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
720
+ { type: 'payment' as const, destination: 'rAnotherAccount', amount: '2000000' },
721
+ ];
722
+
723
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
724
+
725
+ const tx = decodeTransaction(result);
726
+ expect(tx.TransactionType).toBe('Batch');
727
+ expect(tx.Account).toBe(mockAccount);
728
+ expect(tx.Flags).toBe(tfAllOrNothing);
729
+ expect(tx.RawTransactions).toHaveLength(2);
730
+ });
731
+
732
+ it('should build batch with trust-set transactions', async () => {
733
+ const innerTransactions = [
734
+ { type: 'trust-set' as const, currency: 'USD', issuer: mockIssuer, amount: '1000000' },
735
+ ];
736
+
737
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
738
+
739
+ const tx = decodeTransaction(result);
740
+ const rawTx = (tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>)[0];
741
+ expect(rawTx.RawTransaction.TransactionType).toBe('TrustSet');
742
+ expect(rawTx.RawTransaction.Flags).toBe(tfInnerBatchTxn);
743
+ });
744
+
745
+ it('should build batch with nft-mint transactions', async () => {
746
+ const innerTransactions = [{ type: 'nft-mint' as const }];
747
+
748
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
749
+
750
+ const tx = decodeTransaction(result);
751
+ const rawTx = (tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>)[0];
752
+ expect(rawTx.RawTransaction.TransactionType).toBe('NFTokenMint');
753
+ });
754
+
755
+ it('should build batch with token payment', async () => {
756
+ const innerTransactions = [
757
+ {
758
+ type: 'payment' as const,
759
+ destination: mockDestination,
760
+ amount: '100',
761
+ currency: 'USD',
762
+ issuer: mockIssuer,
763
+ },
764
+ ];
765
+
766
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
767
+
768
+ const tx = decodeTransaction(result);
769
+ const rawTx = (tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>)[0];
770
+ expect(rawTx.RawTransaction.Amount).toEqual({
771
+ currency: 'USD',
772
+ issuer: mockIssuer,
773
+ value: '100',
774
+ });
775
+ });
776
+
777
+ it('should build batch with default payment for unknown type', async () => {
778
+ const innerTransactions = [{ type: 'unknown' as any }];
779
+
780
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
781
+
782
+ const tx = decodeTransaction(result);
783
+ const rawTx = (tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>)[0];
784
+ expect(rawTx.RawTransaction.TransactionType).toBe('Payment');
785
+ expect(rawTx.RawTransaction.Amount).toBe('1');
786
+ });
787
+
788
+ it('should set correct sequence numbers for inner transactions', async () => {
789
+ const innerTransactions = [
790
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
791
+ { type: 'payment' as const, destination: mockDestination, amount: '2000000' },
792
+ { type: 'payment' as const, destination: mockDestination, amount: '3000000' },
793
+ ];
794
+
795
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
796
+
797
+ const tx = decodeTransaction(result);
798
+ const rawTxs = tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>;
799
+ expect(rawTxs[0].RawTransaction.Sequence).toBe(1);
800
+ expect(rawTxs[1].RawTransaction.Sequence).toBe(2);
801
+ expect(rawTxs[2].RawTransaction.Sequence).toBe(3);
802
+ });
803
+
804
+ it('should set Fee to 0 and empty SigningPubKey for inner transactions', async () => {
805
+ const innerTransactions = [
806
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
807
+ ];
808
+
809
+ const result = await service.buildBatchTransaction(mockAccount, innerTransactions);
810
+
811
+ const tx = decodeTransaction(result);
812
+ const rawTx = (tx.RawTransactions as Array<{ RawTransaction: Record<string, unknown> }>)[0];
813
+ expect(rawTx.RawTransaction.Fee).toBe('0');
814
+ expect(rawTx.RawTransaction.SigningPubKey).toBe('');
815
+ });
816
+ });
817
+
818
+ describe('buildBatchInnerTransactions', () => {
819
+ it('should build inner transactions with payment (XRP)', async () => {
820
+ const innerTransactions = [
821
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
822
+ ];
823
+
824
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
825
+
826
+ expect(result).toHaveLength(1);
827
+ expect(result[0].payload).toBeDefined();
828
+ expect(result[0].description).toContain('Send');
829
+ expect(result[0].description).toContain('XRP');
830
+ });
831
+
832
+ it('should build inner transactions with payment (token)', async () => {
833
+ const innerTransactions = [
834
+ {
835
+ type: 'payment' as const,
836
+ destination: mockDestination,
837
+ amount: '100',
838
+ currency: 'USD',
839
+ issuer: mockIssuer,
840
+ },
841
+ ];
842
+
843
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
844
+
845
+ expect(result[0].description).toContain('100 USD');
846
+ });
847
+
848
+ it('should build inner transactions with trust-set', async () => {
849
+ const innerTransactions = [
850
+ { type: 'trust-set' as const, currency: 'EUR', issuer: mockIssuer, amount: '500000' },
851
+ ];
852
+
853
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
854
+
855
+ expect(result[0].description).toContain('trust line');
856
+ expect(result[0].description).toContain('EUR');
857
+ });
858
+
859
+ it('should build inner transactions with nft-mint', async () => {
860
+ const innerTransactions = [
861
+ { type: 'nft-mint' as const, uri: '697066733A2F2F', taxon: 42 },
862
+ ];
863
+
864
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
865
+
866
+ expect(result[0].description).toContain('Mint NFT');
867
+ expect(result[0].description).toContain('42');
868
+ });
869
+
870
+ it('should throw error for unknown transaction type', async () => {
871
+ const innerTransactions = [{ type: 'invalid-type' as any }];
872
+
873
+ await expect(
874
+ service.buildBatchInnerTransactions(mockAccount, innerTransactions)
875
+ ).rejects.toThrow('Unknown transaction type');
876
+ });
877
+
878
+ it('should return base64 encoded payloads', async () => {
879
+ const innerTransactions = [
880
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
881
+ ];
882
+
883
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
884
+
885
+ // Verify it's valid base64
886
+ expect(() => atob(result[0].payload)).not.toThrow();
887
+ });
888
+
889
+ it('should build multiple inner transactions', async () => {
890
+ const innerTransactions = [
891
+ { type: 'payment' as const, destination: mockDestination, amount: '1000000' },
892
+ { type: 'trust-set' as const, currency: 'USD', issuer: mockIssuer },
893
+ { type: 'nft-mint' as const, taxon: 0 },
894
+ ];
895
+
896
+ const result = await service.buildBatchInnerTransactions(mockAccount, innerTransactions);
897
+
898
+ expect(result).toHaveLength(3);
899
+ expect(result[0].description).toContain('XRP');
900
+ expect(result[1].description).toContain('trust line');
901
+ expect(result[2].description).toContain('NFT');
902
+ });
903
+ });
904
+
905
+ // ==================== SERIALIZATION ====================
906
+ describe('serializeTransaction', () => {
907
+ it('should produce valid base64 output', async () => {
908
+ const result = await service.buildPayment(mockAccount, mockDestination, '1000000');
909
+
910
+ // Should be valid base64
911
+ expect(() => atob(result)).not.toThrow();
912
+
913
+ // Should produce valid JSON when decoded
914
+ const decoded = atob(result);
915
+ expect(() => JSON.parse(decoded)).not.toThrow();
916
+ });
917
+
918
+ it('should preserve all transaction fields', async () => {
919
+ const result = await service.buildPayment(
920
+ mockAccount,
921
+ mockDestination,
922
+ '100',
923
+ true,
924
+ 'USD',
925
+ mockIssuer
926
+ );
927
+
928
+ const tx = decodeTransaction(result);
929
+
930
+ // Verify all expected fields are present
931
+ expect(tx).toHaveProperty('TransactionType');
932
+ expect(tx).toHaveProperty('Account');
933
+ expect(tx).toHaveProperty('Destination');
934
+ expect(tx).toHaveProperty('Amount');
935
+ });
936
+ });
937
+ });