diff --git a/src/containers/Transactions/test/SimpleTab.test.tsx b/src/containers/Transactions/test/SimpleTab.test.tsx
index 652ded5b7..bce4d5502 100644
--- a/src/containers/Transactions/test/SimpleTab.test.tsx
+++ b/src/containers/Transactions/test/SimpleTab.test.tsx
@@ -9,23 +9,36 @@ import { SimpleTab } from '../SimpleTab'
import summarize from '../../../rippled/lib/txSummary'
import i18n from '../../../i18n/testConfig'
import { expectSimpleRowText } from '../../shared/components/Transaction/test'
+import SocketContext from '../../shared/SocketContext'
+import MockWsClient from '../../test/mockWsClient'
import { queryClient } from '../../shared/QueryClient'
describe('SimpleTab container', () => {
+ let client
const createWrapper = (tx, width = 1200) =>
mount(
-
+
+
+
,
)
+ beforeEach(() => {
+ client = new MockWsClient()
+ })
+
+ afterEach(() => {
+ client.close()
+ })
+
it('renders EnableAmendment without crashing', () => {
const wrapper = createWrapper(EnableAmendment)
wrapper.unmount()
diff --git a/src/containers/shared/amendmentUtils.ts b/src/containers/shared/amendmentUtils.ts
index 96e189e33..b9e21af55 100644
--- a/src/containers/shared/amendmentUtils.ts
+++ b/src/containers/shared/amendmentUtils.ts
@@ -1,14 +1,9 @@
-import { sha512 } from '@xrplf/isomorphic/sha512'
-import { hexToBytes, bytesToHex, stringToHex } from '@xrplf/isomorphic/utils'
import axios from 'axios'
import { localizeDate } from './utils'
-const cachedAmendmentIDs: any = {}
let cachedRippledVersions: any = {}
-const ACTIVE_AMENDMENT_REGEX = /^\s*REGISTER_F[A-Z]+\s*\((\S+),\s*.*$/
-const RETIRED_AMENDMENT_REGEX = /^ .*retireFeature\("(\S+)"\)[,;].*$/
const TIME_ZONE = 'UTC'
const DATE_OPTIONS = {
hour: 'numeric',
@@ -31,42 +26,6 @@ export function getExpectedDate(date: string, language: string) {
)
}
-async function fetchAmendmentNames() {
- const response = await axios.get(
- 'https://raw.githubusercontent.com/XRPLF/rippled/develop/src/libxrpl/protocol/Feature.cpp',
- )
- const text = response.data
-
- const amendmentNames: string[] = []
- text.split('\n').forEach((line: string) => {
- const name = line.match(ACTIVE_AMENDMENT_REGEX)
- if (name) {
- amendmentNames.push(name[1])
- } else {
- const name2 = line.match(RETIRED_AMENDMENT_REGEX)
- name2 && amendmentNames.push(name2[1])
- }
- })
- return amendmentNames
-}
-
-function sha512Half(bytes: Uint8Array) {
- return bytesToHex(sha512(bytes)).slice(0, 64)
-}
-
-export async function nameOfAmendmentID(id: string) {
- if (cachedAmendmentIDs[id]) {
- return cachedAmendmentIDs[id]
- }
- // The Amendment ID is the hash of the Amendment name
- const amendmentNames = await fetchAmendmentNames()
- amendmentNames.forEach((name) => {
- cachedAmendmentIDs[sha512Half(hexToBytes(stringToHex(name)))] = name
- })
-
- return cachedAmendmentIDs[id]
-}
-
async function fetchMinRippledVersions() {
const response = await axios.get(
'https://raw.githubusercontent.com/XRPLF/xrpl-dev-portal/master/resources/known-amendments.md',
diff --git a/src/containers/shared/components/Transaction/EnableAmendment/Simple.tsx b/src/containers/shared/components/Transaction/EnableAmendment/Simple.tsx
index 184faee53..35f885c53 100644
--- a/src/containers/shared/components/Transaction/EnableAmendment/Simple.tsx
+++ b/src/containers/shared/components/Transaction/EnableAmendment/Simple.tsx
@@ -1,15 +1,13 @@
-import { useEffect, useState } from 'react'
+import { useContext, useEffect, useState } from 'react'
import { useLanguage } from '../../../hooks'
import { SimpleRow } from '../SimpleRow'
import { TransactionSimpleProps } from '../types'
import { EnableAmendment } from './types'
-import {
- getExpectedDate,
- getRippledVersion,
- nameOfAmendmentID,
-} from '../../../amendmentUtils'
+import { getExpectedDate, getRippledVersion } from '../../../amendmentUtils'
import { AMENDMENT_ROUTE } from '../../../../App/routes'
import { RouteLink } from '../../../routing'
+import SocketContext from '../../../SocketContext'
+import { getFeature } from '../../../../../rippled/lib/rippled'
const states = {
loading: 'Loading',
@@ -22,31 +20,21 @@ export const Simple = ({ data }: TransactionSimpleProps) => {
name: states.loading,
minRippledVersion: states.loading,
})
+ const rippledSocket = useContext(SocketContext)
useEffect(() => {
- nameOfAmendmentID(data.instructions.Amendment).then((name: string) => {
- if (name) {
- getRippledVersion(name).then((rippledVersion) => {
- if (rippledVersion) {
- setAmendmentDetails({
- name,
- minRippledVersion: rippledVersion,
- })
- } else {
- setAmendmentDetails({
- name,
- minRippledVersion: states.unknown,
- })
- }
- })
- } else {
+ const amendmentId = data.instructions.Amendment
+ getFeature(rippledSocket, amendmentId).then((feature) => {
+ const name =
+ feature && feature[amendmentId] ? feature[amendmentId].name : ''
+ getRippledVersion(name).then((rippledVersion) => {
setAmendmentDetails({
- name: states.unknown,
- minRippledVersion: states.unknown,
+ name: name || states.unknown,
+ minRippledVersion: rippledVersion || states.unknown,
})
- }
+ })
})
- }, [data.instructions.Amendment])
+ }, [data.instructions.Amendment, rippledSocket])
let amendmentStatus = states.unknown
let expectedDate: string | null = states.unknown
diff --git a/src/containers/shared/components/Transaction/EnableAmendment/test/EnableAmendmentSimple.test.tsx b/src/containers/shared/components/Transaction/EnableAmendment/test/EnableAmendmentSimple.test.tsx
index d04002da3..476931b4d 100644
--- a/src/containers/shared/components/Transaction/EnableAmendment/test/EnableAmendmentSimple.test.tsx
+++ b/src/containers/shared/components/Transaction/EnableAmendment/test/EnableAmendmentSimple.test.tsx
@@ -6,11 +6,11 @@ import { Simple } from '../Simple'
import mockEnableAmendmentWithEnabled from './mock_data/EnableAmendmentWithEnabled.json'
import mockEnableAmendmentWithMinority from './mock_data/EnableAmendmentWithMinority.json'
import mockEnableAmendmentWithMajority from './mock_data/EnableAmendmentWithMajority.json'
-import {
- getRippledVersion,
- nameOfAmendmentID,
-} from '../../../../amendmentUtils'
+import mockFeatureExpandedSignerList from './mock_data/FeatureExpandedSignerList.json'
+import mockFeatureNegativeUNL from './mock_data/FeatureNegativeUNL.json'
+import { getRippledVersion } from '../../../../amendmentUtils'
import { flushPromises } from '../../../../../test/utils'
+import { getFeature } from '../../../../../../rippled/lib/rippled'
const createWrapper = createSimpleWrapperFactory(Simple, i18n)
@@ -21,22 +21,35 @@ jest.mock('../../../../amendmentUtils', () => {
__esModule: true,
...originalModule,
getRippledVersion: jest.fn(),
- nameOfAmendmentID: jest.fn(),
+ }
+})
+
+jest.mock('../../../../../../rippled/lib/rippled', () => {
+ const originalModule = jest.requireActual(
+ '../../../../../../rippled/lib/rippled',
+ )
+
+ return {
+ __esModule: true,
+ ...originalModule,
+ getFeature: jest.fn(),
}
})
const mockedGetRippledVersion = getRippledVersion as jest.MockedFunction<
typeof getRippledVersion
>
-const mockedNameOfAmendmentID = nameOfAmendmentID as jest.MockedFunction<
- typeof nameOfAmendmentID
->
+
+const mockedGetFeature = getFeature as jest.MockedFunction
describe('EnableAmendment: Simple', () => {
+ afterEach(() => {
+ mockedGetFeature.mockReset()
+ })
it('renders tx that causes an amendment to loose majority', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve('v1.9.1'))
- mockedNameOfAmendmentID.mockImplementation(() =>
- Promise.resolve('ExpandedSignerList'),
+ mockedGetFeature.mockImplementation(() =>
+ Promise.resolve(mockFeatureExpandedSignerList),
)
const wrapper = createWrapper(mockEnableAmendmentWithMinority)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
@@ -58,8 +71,8 @@ describe('EnableAmendment: Simple', () => {
it('renders tx that causes an amendment to gain majority', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve('v1.9.1'))
- mockedNameOfAmendmentID.mockImplementation(() =>
- Promise.resolve('ExpandedSignerList'),
+ mockedGetFeature.mockImplementation(() =>
+ Promise.resolve(mockFeatureExpandedSignerList),
)
const wrapper = createWrapper(mockEnableAmendmentWithMajority)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
@@ -86,8 +99,8 @@ describe('EnableAmendment: Simple', () => {
it('renders tx that enables an amendment', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve('v1.7.3'))
- mockedNameOfAmendmentID.mockImplementation(() =>
- Promise.resolve('NegativeUNL'),
+ mockedGetFeature.mockImplementation(() =>
+ Promise.resolve(mockFeatureNegativeUNL),
)
const wrapper = createWrapper(mockEnableAmendmentWithEnabled)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
@@ -108,7 +121,7 @@ describe('EnableAmendment: Simple', () => {
it('renders tx that cannot determine version or name', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve(''))
- mockedNameOfAmendmentID.mockImplementation(() => Promise.resolve(''))
+ mockedGetFeature.mockImplementation(() => Promise.resolve(null))
const wrapper = createWrapper(mockEnableAmendmentWithEnabled)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
expectSimpleRowText(wrapper, 'name', 'Loading')
@@ -124,8 +137,8 @@ describe('EnableAmendment: Simple', () => {
it('renders tx that cannot determine version', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve(''))
- mockedNameOfAmendmentID.mockImplementation(() =>
- Promise.resolve('NegativeUNL'),
+ mockedGetFeature.mockImplementation(() =>
+ Promise.resolve(mockFeatureNegativeUNL),
)
const wrapper = createWrapper(mockEnableAmendmentWithEnabled)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
@@ -142,7 +155,7 @@ describe('EnableAmendment: Simple', () => {
it('renders tx that cannot determine name', async () => {
mockedGetRippledVersion.mockImplementation(() => Promise.resolve('v1.7.3'))
- mockedNameOfAmendmentID.mockImplementation(() => Promise.resolve(''))
+ mockedGetFeature.mockImplementation(() => Promise.resolve(null))
const wrapper = createWrapper(mockEnableAmendmentWithEnabled)
expectSimpleRowLabel(wrapper, 'name', 'Amendment Name')
expectSimpleRowText(wrapper, 'name', 'Loading')
@@ -153,6 +166,6 @@ describe('EnableAmendment: Simple', () => {
wrapper.update()
expectSimpleRowText(wrapper, 'name', 'Unknown')
- expectSimpleRowText(wrapper, 'version', 'Unknown')
+ expectSimpleRowText(wrapper, 'version', 'v1.7.3')
})
})
diff --git a/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureExpandedSignerList.json b/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureExpandedSignerList.json
new file mode 100644
index 000000000..09635f407
--- /dev/null
+++ b/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureExpandedSignerList.json
@@ -0,0 +1,7 @@
+{
+ "B2A4DB846F0891BF2C76AB2F2ACC8F5B4EC64437135C6E56F3F859DE5FFD5856": {
+ "enabled": false,
+ "name": "ExpandedSignerList",
+ "supported": true
+ }
+}
diff --git a/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureNegativeUNL.json b/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureNegativeUNL.json
new file mode 100644
index 000000000..56341a552
--- /dev/null
+++ b/src/containers/shared/components/Transaction/EnableAmendment/test/mock_data/FeatureNegativeUNL.json
@@ -0,0 +1,7 @@
+{
+ "B4E4F5D2D6FB84DF7399960A732309C9FD530EAE5941838160042833625A6076": {
+ "enabled": false,
+ "name": "NegativeUNL",
+ "supported": true
+ }
+}
diff --git a/src/containers/shared/test/amendmentUtils.test.ts b/src/containers/shared/test/amendmentUtils.test.ts
index f7f21e645..e4ef9d4e6 100644
--- a/src/containers/shared/test/amendmentUtils.test.ts
+++ b/src/containers/shared/test/amendmentUtils.test.ts
@@ -1,170 +1,4 @@
-import { getRippledVersion, nameOfAmendmentID } from '../amendmentUtils'
-
-const nameTable = [
- [
- '32A122F1352A4C7B3A6D790362CC34749C5E57FCE896377BFDC6CCD14F6CD627',
- 'NonFungibleTokensV1_1',
- ],
- [
- '4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373',
- 'MultiSign',
- ],
- [
- '6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC',
- 'TrustSetAuth',
- ],
- [
- '42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE',
- 'FeeEscalation',
- ],
- [
- '08DE7D96082187F6E6578530258C77FAABABE4C20474BDB82F04B021F1A68647',
- 'PayChan',
- ],
- ['740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11', 'Flow'],
- [
- '1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146',
- 'CryptoConditions',
- ],
- [
- '532651B4FD58DF8922A49BA101AB3E996E5BFBF95A913B3E392504863E63B164',
- 'TickSize',
- ],
- [
- 'E2E6F2866106419B88C50045ACE96368558C345566AC8F2BDF5A5B5587F0E6FA',
- 'fix1368',
- ],
- [
- '07D43DCE529B15A10827E5E04943B496762F9A88E3268269D69C44BE49E21104',
- 'Escrow',
- ],
- [
- '86E83A7D2ECE3AD5FA87AB2195AE015C950469ABF0B72EAACED318F74886AE90',
- 'CryptoConditionsSuite',
- ],
- [
- '42EEA5E28A97824821D4EF97081FE36A54E9593C6E4F20CBAE098C69D2E072DC',
- 'fix1373',
- ],
- [
- 'DC9CA96AEA1DCF83E527D1AFC916EFAF5D27388ECA4060A88817C1238CAEE0BF',
- 'EnforceInvariants',
- ],
- [
- '3012E8230864E95A58C60FD61430D7E1B4D3353195F2981DC12B0C7C0950FFAC',
- 'FlowCross',
- ],
- [
- 'CC5ABAE4F3EC92E94A59B1908C2BE82D2228B6485C00AFF8F22DF930D89C194E',
- 'SortedDirectories',
- ],
- [
- 'B4D44CC3111ADD964E846FC57760C8B50FFCD5A82C86A72756F6B058DDDF96AD',
- 'fix1201',
- ],
- [
- '6C92211186613F9647A89DFFBAB8F94C99D4C7E956D495270789128569177DA1',
- 'fix1512',
- ],
- [
- '67A34F2CF55BFC0F93AACD5B281413176FEE195269FA6D95219A2DF738671172',
- 'fix1513',
- ],
- [
- 'B9E739B8296B4A1BB29BE990B17D66E21B62A300A909F25AC55C22D6C72E1F9D',
- 'fix1523',
- ],
- [
- '1D3463A5891F9E589C5AE839FFAC4A917CE96197098A1EF22304E1BC5B98A454',
- 'fix1528',
- ],
- [
- 'F64E1EABBE79D55B3BB82020516CEC2C582A98A6BFE20FBE9BB6A0D233418064',
- 'DepositAuth',
- ],
- [
- '157D2D480E006395B76F948E3E07A45A05FE10230D88A7993C71F97AE4B1F2D1',
- 'Checks',
- ],
- [
- '7117E2EC2DBF119CA55181D69819F1999ECEE1A0225A7FD2B9ED47940968479C',
- 'fix1571',
- ],
- [
- 'CA7C02118BA27599528543DFE77BA6838D1B0F43B447D4D7F53523CE6A0E9AC2',
- 'fix1543',
- ],
- [
- '58BE9B5968C4DA7C59BA900961828B113E5490699B21877DEF9A31E9D0FE5D5F',
- 'fix1623',
- ],
- [
- '3CBC5C4E630A1B82380295CDA84B32B49DD066602E74E39B85EF64137FA65194',
- 'DepositPreauth',
- ],
- [
- '5D08145F0A4983F23AFFFF514E83FAD355C5ABFBB6CAB76FB5BC8519FF5F33BE',
- 'fix1515',
- ],
- [
- 'FBD513F1B893AC765B78F250E6FFA6A11B573209D1842ADC787C850696741288',
- 'fix1578',
- ],
- [
- '586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF1FC07EFE41D',
- 'MultiSignReserve',
- ],
- [
- '2CD5286D8D687E98B41102BDD797198E81EA41DF7BD104E6561FEB104EFF2561',
- 'fixTakerDryOfferRemoval',
- ],
- [
- 'C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD37',
- 'fixMasterKeyAsRegularKey',
- ],
- [
- '8F81B066ED20DAECA20DF57187767685EEF3980B228E0667A650BAF24426D3B4',
- 'fixCheckThreading',
- ],
- [
- '621A0B264970359869E3C0363A899909AAB7A887C8B73519E4ECF952D33258A8',
- 'fixPayChanRecipientOwnerDir',
- ],
- [
- '30CD365592B8EE40489BA01AE2F7555CAC9C983145871DC82A42A31CF5BAE7D9',
- 'DeletableAccounts',
- ],
- [
- '89308AF3B8B10B7192C4E613E1D2E4D9BA64B2EE2D5232402AE82A6A7220D953',
- 'fixQualityUpperBound',
- ],
- [
- '00C1FC4A53E60AB02C864641002B3172F38677E29C26C5406685179B37E1EDAC',
- 'RequireFullyCanonicalSig',
- ],
- [
- '25BA44241B3BD880770BFA4DA21C7180576831855368CBEC6A3154FDE4A7676E',
- 'fix1781',
- ],
- [
- '1F4AFA8FA1BC8827AD4C0F682C03A8B671DCDF6B5C4DE36D44243A684103EF88',
- 'HardenedValidations',
- ],
- [
- '4F46DF03559967AC60F2EB272FEFE3928A7594A45FF774B87A7E540DB0F8F068',
- 'fixAmendmentMajorityCalc',
- ],
-]
-
-describe('nameOfAmendmentID: ', () => {
- it.each(nameTable)(
- `should resolve amendment id "%s" to "%s"`,
- async (id, name) => {
- const retrievedName = await nameOfAmendmentID(id)
- return expect(retrievedName).toEqual(name)
- },
- )
-})
+import { getRippledVersion } from '../amendmentUtils'
const versionTable = [
['NonFungibleTokensV1_1', 'v1.9.2'],
diff --git a/src/rippled/lib/rippled.js b/src/rippled/lib/rippled.js
index c77c6584d..dc7737309 100644
--- a/src/rippled/lib/rippled.js
+++ b/src/rippled/lib/rippled.js
@@ -557,6 +557,21 @@ const getAMMInfo = (rippledSocket, asset, asset2) => {
})
}
+// get feature
+const getFeature = (rippledSocket, amendmentId) => {
+ const request = {
+ command: 'feature',
+ feature: amendmentId,
+ }
+ return query(rippledSocket, request).then((resp) => {
+ if (resp == null || resp.error_message) {
+ return null
+ }
+
+ return resp
+ })
+}
+
const getMPTIssuance = (rippledSocket, tokenId) =>
query(rippledSocket, {
command: 'ledger_entry',
@@ -624,6 +639,7 @@ export {
getSellNFToffers,
getNFTTransactions,
getAMMInfo,
+ getFeature,
getMPTIssuance,
getAccountMPTs,
}