) => {
const { tx } = data
- const { Account: account, VaultID: vaultId } = tx
+ const { Account: account, VaultID: vaultId, MemoData: memoData } = tx
return (
- ,
- VaultID: {vaultId},
- }}
- />
+ <>
+ ,
+ VaultID: {vaultId},
+ }}
+ />
+ {memoData && hexMatch.test(memoData) && (
+
+ {decodeHex(memoData)},
+ }}
+ />
+
+ )}
+ >
)
}
diff --git a/src/containers/shared/components/Transaction/VaultDelete/Simple.tsx b/src/containers/shared/components/Transaction/VaultDelete/Simple.tsx
index 3d92f77a9..8744966ae 100644
--- a/src/containers/shared/components/Transaction/VaultDelete/Simple.tsx
+++ b/src/containers/shared/components/Transaction/VaultDelete/Simple.tsx
@@ -2,16 +2,32 @@ import { useTranslation } from 'react-i18next'
import type { VaultDelete } from 'xrpl'
import { TransactionSimpleComponent, TransactionSimpleProps } from '../types'
import { SimpleRow } from '../SimpleRow'
+import { decodeHex, hexMatch } from '../../../transactionUtils'
export const Simple: TransactionSimpleComponent = (
props: TransactionSimpleProps,
) => {
const { t } = useTranslation()
const { data } = props
- const { VaultID: vaultId } = data.instructions
+ const { VaultID: vaultId, MemoData: memoData } = data.instructions
return (
-
- {vaultId}
-
+ <>
+
+ {vaultId}
+
+ {memoData && hexMatch.test(memoData) && (
+
+ {decodeHex(memoData)}
+
+ )}
+ >
)
}
diff --git a/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteDescription.test.tsx b/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteDescription.test.tsx
index 961aa1f09..c6e4af1b7 100644
--- a/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteDescription.test.tsx
+++ b/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteDescription.test.tsx
@@ -11,6 +11,9 @@ describe('VaultDelete: Description', () => {
expect(container).toHaveTextContent(
'rLR12AgChXxLoQsuLCizNCgh5pt5jPheo1 deleted a vault with ID 2AA88C4CA646645E35E38B8D51CD2CA50BDE14A3F3FFE3838F2C8DCE95C2BABD',
)
+ expect(container).toHaveTextContent(
+ 'It sets the Vault deletion MemoData to vault closed voluntarily',
+ )
unmount()
})
})
diff --git a/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteSimple.test.tsx b/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteSimple.test.tsx
index 3880d761c..9e21bb0d4 100644
--- a/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteSimple.test.tsx
+++ b/src/containers/shared/components/Transaction/VaultDelete/test/VaultDeleteSimple.test.tsx
@@ -12,6 +12,7 @@ describe('VaultDelete: Simple', () => {
'vault_id',
'2AA88C4CA646645E35E38B8D51CD2CA50BDE14A3F3FFE3838F2C8DCE95C2BABD',
)
+ expectSimpleRowText(container, 'memo_data', 'vault closed voluntarily')
unmount()
})
})
diff --git a/src/containers/shared/components/Transaction/VaultDelete/test/mock_data/VaultDelete.json b/src/containers/shared/components/Transaction/VaultDelete/test/mock_data/VaultDelete.json
index 853977db5..62d56f5c5 100644
--- a/src/containers/shared/components/Transaction/VaultDelete/test/mock_data/VaultDelete.json
+++ b/src/containers/shared/components/Transaction/VaultDelete/test/mock_data/VaultDelete.json
@@ -180,6 +180,7 @@
"TransactionType": "VaultDelete",
"TxnSignature": "D6A3F0AADD0ECEE2D51E051157EF582D8C1EFD84897A912557148FC963D9B93DFD725996F90ED2DF7F0922B34E47D28869E408EDD9F7CA2CEA681023EE57B70D",
"VaultID": "2AA88C4CA646645E35E38B8D51CD2CA50BDE14A3F3FFE3838F2C8DCE95C2BABD",
+ "MemoData": "7661756C7420636C6F73656420766F6C756E746172696C79",
"ctid": "C00626A700000C96",
"date": 807127481,
"ledger_index": 403111
diff --git a/src/containers/shared/components/Transaction/VaultDeposit/Simple.tsx b/src/containers/shared/components/Transaction/VaultDeposit/Simple.tsx
index dc19a7ab5..014a169e8 100644
--- a/src/containers/shared/components/Transaction/VaultDeposit/Simple.tsx
+++ b/src/containers/shared/components/Transaction/VaultDeposit/Simple.tsx
@@ -13,7 +13,11 @@ export const Simple: TransactionSimpleComponent = (
const { VaultID: vaultId, Amount: amount } = data.instructions
return (
<>
-
+
{vaultId}
diff --git a/src/containers/shared/components/Transaction/VaultSet/Simple.tsx b/src/containers/shared/components/Transaction/VaultSet/Simple.tsx
index 525f8e527..9777eefbc 100644
--- a/src/containers/shared/components/Transaction/VaultSet/Simple.tsx
+++ b/src/containers/shared/components/Transaction/VaultSet/Simple.tsx
@@ -13,7 +13,11 @@ export const Simple: TransactionSimpleComponent = (
const { VaultID, Data, AssetsMaximum, DomainID } = data.instructions
return (
<>
-
+
{VaultID}
{AssetsMaximum && (
diff --git a/src/containers/shared/components/Transaction/VaultWithdraw/Simple.tsx b/src/containers/shared/components/Transaction/VaultWithdraw/Simple.tsx
index 594d15cf0..9a1f0c850 100644
--- a/src/containers/shared/components/Transaction/VaultWithdraw/Simple.tsx
+++ b/src/containers/shared/components/Transaction/VaultWithdraw/Simple.tsx
@@ -5,6 +5,7 @@ import { SimpleRow } from '../SimpleRow'
import { Amount } from '../../Amount'
import { formatAmount } from '../../../../../rippled/lib/txSummary/formatAmount'
import { Account } from '../../Account'
+import { CredentialIDs } from '../CredentialIDs'
export const Simple: TransactionSimpleComponent = (
props: TransactionSimpleProps,
@@ -15,10 +16,15 @@ export const Simple: TransactionSimpleComponent = (
VaultID: vaultId,
Amount: amount,
Destination: destination,
+ CredentialIDs: credentialIds,
} = data.instructions
return (
<>
-
+
{vaultId}
@@ -29,6 +35,9 @@ export const Simple: TransactionSimpleComponent = (
)}
+ {credentialIds && credentialIds.length > 0 && (
+
+ )}
>
)
}
diff --git a/src/containers/shared/components/Transaction/VaultWithdraw/test/VaultWithdrawSimple.test.tsx b/src/containers/shared/components/Transaction/VaultWithdraw/test/VaultWithdrawSimple.test.tsx
index 4874c7e94..afeb39e2e 100644
--- a/src/containers/shared/components/Transaction/VaultWithdraw/test/VaultWithdrawSimple.test.tsx
+++ b/src/containers/shared/components/Transaction/VaultWithdraw/test/VaultWithdrawSimple.test.tsx
@@ -1,6 +1,7 @@
import { expectSimpleRowText, createSimpleRenderFactory } from '../../test'
import { Simple } from '../Simple'
import mockVaultWithdraw from './mock_data/VaultWithdraw.json'
+import mockVaultWithdrawWithCredentials from './mock_data/VaultWithdrawWithCredentials.json'
const renderComponent = createSimpleRenderFactory(Simple)
@@ -17,6 +18,26 @@ describe('VaultWithdraw: Simple', () => {
'amount',
'$5.00 USD.rMab3itPzruo5HLEVherc93Prf4tg5d7dx',
)
+ expect(
+ container.querySelector('[data-testid="credential-id-0"]'),
+ ).not.toBeInTheDocument()
+ unmount()
+ })
+
+ it('renders credential IDs for a permissioned-domain withdrawal', () => {
+ const { container, unmount } = renderComponent(
+ mockVaultWithdrawWithCredentials,
+ )
+ expect(
+ container.querySelector('[data-testid="credential-id-0"]'),
+ ).toHaveTextContent(
+ 'EA85E9D5B4F0D8E36C5F1A4B8C2D3E4F5061728394A5B6C7D8E9F0A1B2C3D4E5',
+ )
+ expect(
+ container.querySelector('[data-testid="credential-id-1"]'),
+ ).toHaveTextContent(
+ 'FB96FAE6C501E9F47D6F2B5C9D3E4F5061728394A5B6C7D8E9F0A1B2C3D4E5F6',
+ )
unmount()
})
})
diff --git a/src/containers/shared/components/Transaction/VaultWithdraw/test/mock_data/VaultWithdrawWithCredentials.json b/src/containers/shared/components/Transaction/VaultWithdraw/test/mock_data/VaultWithdrawWithCredentials.json
new file mode 100644
index 000000000..3f4261dbb
--- /dev/null
+++ b/src/containers/shared/components/Transaction/VaultWithdraw/test/mock_data/VaultWithdrawWithCredentials.json
@@ -0,0 +1,194 @@
+{
+ "close_time_iso": "2025-07-29T16:47:21Z",
+ "ctid": "C006209F00000C96",
+ "hash": "372CD0ABA6ED9E375A3042AC8F47D5C6A25D4C88077547C1FE2991B3CF3A1382",
+ "ledger_hash": "6DBE1C014D47E0D8BA4267C1D54E51B539EAA01AAAD417403B78DA474C850485",
+ "ledger_index": 401567,
+ "meta": {
+ "AffectedNodes": [
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Flags": 56,
+ "Issuer": "rER4URMRoAvPPbPVWqycZdK85rhJwRnQCB",
+ "MPTokenMetadata": "7368617265206D65746164617461",
+ "OutstandingAmount": "5",
+ "OwnerNode": "0",
+ "Sequence": 1
+ },
+ "LedgerEntryType": "MPTokenIssuance",
+ "LedgerIndex": "259D6E5DB97AC2329F153BD53077B9EF08C73ED6A8F95C88DBDA9FAF60E18DA4",
+ "PreviousFields": {
+ "OutstandingAmount": "10"
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ },
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Account": "rQEzyNVohiNuWwYFnwUMEWeyK3KvACUbyB",
+ "Flags": 0,
+ "MPTAmount": "5",
+ "MPTokenIssuanceID": "000000019E2D7036879DFC217D7D2A92CC7349EEB0D703AA",
+ "OwnerNode": "0"
+ },
+ "LedgerEntryType": "MPToken",
+ "LedgerIndex": "267C99D9B622D5F661117E51E0F58BDB03D3F077F381EB395CCD6AC8BE882AE9",
+ "PreviousFields": {
+ "MPTAmount": "10"
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ },
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Account": "rQEzyNVohiNuWwYFnwUMEWeyK3KvACUbyB",
+ "Balance": "89999988",
+ "Flags": 0,
+ "OwnerCount": 2,
+ "Sequence": 401557
+ },
+ "LedgerEntryType": "AccountRoot",
+ "LedgerIndex": "544FECF19CF124E5D93D1A7D4973BDAA536C6D3DF8579A3E975445AD27542F52",
+ "PreviousFields": {
+ "Balance": "94999988",
+ "Sequence": 401556
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ },
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Balance": {
+ "currency": "USD",
+ "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
+ "value": "-995"
+ },
+ "Flags": 131072,
+ "HighLimit": {
+ "currency": "USD",
+ "issuer": "rQEzyNVohiNuWwYFnwUMEWeyK3KvACUbyB",
+ "value": "1000"
+ },
+ "HighNode": "0",
+ "LowLimit": {
+ "currency": "USD",
+ "issuer": "rMab3itPzruo5HLEVherc93Prf4tg5d7dx",
+ "value": "0"
+ },
+ "LowNode": "0"
+ },
+ "LedgerEntryType": "RippleState",
+ "LedgerIndex": "62D2CA23FC334A9E56B4EEC9E1F069862D31ED8BEB2A0DBB4A0FAD56E08B8DD4",
+ "PreviousFields": {
+ "Balance": {
+ "currency": "USD",
+ "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
+ "value": "-990"
+ }
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ },
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Balance": {
+ "currency": "USD",
+ "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
+ "value": "5"
+ },
+ "Flags": 1114112,
+ "HighLimit": {
+ "currency": "USD",
+ "issuer": "rMab3itPzruo5HLEVherc93Prf4tg5d7dx",
+ "value": "0"
+ },
+ "HighNode": "0",
+ "LowLimit": {
+ "currency": "USD",
+ "issuer": "rER4URMRoAvPPbPVWqycZdK85rhJwRnQCB",
+ "value": "0"
+ },
+ "LowNode": "0"
+ },
+ "LedgerEntryType": "RippleState",
+ "LedgerIndex": "69D9A5B5C98036058C4BF3FA2C18469268E377416535A7EC57D6AB795F6600D3",
+ "PreviousFields": {
+ "Balance": {
+ "currency": "USD",
+ "issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
+ "value": "10"
+ }
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ },
+ {
+ "ModifiedNode": {
+ "FinalFields": {
+ "Account": "rER4URMRoAvPPbPVWqycZdK85rhJwRnQCB",
+ "Asset": {
+ "currency": "USD",
+ "issuer": "rMab3itPzruo5HLEVherc93Prf4tg5d7dx"
+ },
+ "AssetsAvailable": "5",
+ "AssetsMaximum": "1000",
+ "AssetsTotal": "5",
+ "Data": "75706461746564206D65746164617461",
+ "Flags": 0,
+ "LossUnrealized": "0",
+ "Owner": "rEBAjhUfR1dPfiBKbBtYqyRrXTpyPLFBcM",
+ "OwnerNode": "0",
+ "Sequence": 401553,
+ "ShareMPTID": "000000019E2D7036879DFC217D7D2A92CC7349EEB0D703AA",
+ "WithdrawalPolicy": 1
+ },
+ "LedgerEntryType": "Vault",
+ "LedgerIndex": "FCC4FB21E6F5B3E60661730C7F6F13A100E1E89FF4CF854D9A9B2F3DF967FD77",
+ "PreviousFields": {
+ "AssetsAvailable": "10",
+ "AssetsTotal": "10"
+ },
+ "PreviousTxnID": "2FED432AF524C5CD3D54EC462FD5ADFC77757A8CFFBF1448621AA46F2F941DF5",
+ "PreviousTxnLgrSeq": 401565
+ }
+ }
+ ],
+ "TransactionIndex": 0,
+ "TransactionResult": "tesSUCCESS"
+ },
+ "tx": {
+ "Account": "rQEzyNVohiNuWwYFnwUMEWeyK3KvACUbyB",
+ "Amount": {
+ "currency": "USD",
+ "issuer": "rMab3itPzruo5HLEVherc93Prf4tg5d7dx",
+ "value": "5"
+ },
+ "Fee": "5000000",
+ "Flags": 0,
+ "LastLedgerSequence": 401585,
+ "NetworkID": 3222,
+ "Sequence": 401556,
+ "SigningPubKey": "ED7FCFBD5471DAD24425FE859842671D2285F8653790892F87E1394C0BB8BEE7E9",
+ "TransactionType": "VaultWithdraw",
+ "TxnSignature": "052F1DEE5A92AF3DF48EB252CBA8FC53DFB966C1B90E323CE5C7FCDFCDCB00761A4B462B115F2BAF9FA511BEFDDA1F4F33BACDCF88D03A29094189BF893C7A07",
+ "VaultID": "FCC4FB21E6F5B3E60661730C7F6F13A100E1E89FF4CF854D9A9B2F3DF967FD77",
+ "ctid": "C006209F00000C96",
+ "date": 807122841,
+ "ledger_index": 401567,
+ "CredentialIDs": [
+ "EA85E9D5B4F0D8E36C5F1A4B8C2D3E4F5061728394A5B6C7D8E9F0A1B2C3D4E5",
+ "FB96FAE6C501E9F47D6F2B5C9D3E4F5061728394A5B6C7D8E9F0A1B2C3D4E5F6"
+ ]
+ },
+ "validated": true
+}
diff --git a/src/containers/shared/transactionUtils.ts b/src/containers/shared/transactionUtils.ts
index f537fd3de..0fdc807ea 100644
--- a/src/containers/shared/transactionUtils.ts
+++ b/src/containers/shared/transactionUtils.ts
@@ -40,6 +40,7 @@ export const SPONSOR_SCOPE_LABEL_KEYS = {
export const TX_FLAGS: Record> = {
all: {
0x80000000: 'tfFullyCanonicalSig',
+ 0x40000000: 'tfInnerBatchTxn',
},
AccountSet: {
0x00010000: 'tfRequireDestTag',
diff --git a/src/containers/shared/vaultUtils.ts b/src/containers/shared/vaultUtils.ts
new file mode 100644
index 000000000..f731432d0
--- /dev/null
+++ b/src/containers/shared/vaultUtils.ts
@@ -0,0 +1,20 @@
+/**
+ * Shared Single Asset Vault helpers.
+ *
+ * VaultKind distinguishes a closed-ended vault from the default open-ended
+ * kind, and is gated behind the `LendingProtocolV1_1` amendment. A closed-ended
+ * vault also carries a SubscriptionDate/RedemptionDate pair, and is the only
+ * kind a LoanBroker may be attached to.
+ */
+
+// Translation keys, so the caller can render these via t().
+export const VAULT_KIND_OPEN_ENDED = 'open_ended'
+export const VAULT_KIND_CLOSED_ENDED = 'closed_ended'
+
+// VaultKind values from the XLS-65d spec.
+export const VAULT_KINDS: {
+ [key: number]: typeof VAULT_KIND_OPEN_ENDED | typeof VAULT_KIND_CLOSED_ENDED
+} = {
+ 0: VAULT_KIND_OPEN_ENDED,
+ 1: VAULT_KIND_CLOSED_ENDED,
+}