-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for
SetHook
transaction (#757)
## High Level Overview of Change Title says it all. ### Context of Change Better hooks support ### Type of Change - [x] New feature (non-breaking change which adds functionality) ### TypeScript/Hooks Update Files added used TS/hooks ## Before / After `SetHook` now has a custom `Simple` page. ![image](https://github.com/ripple/explorer/assets/8029314/7b6b7875-9997-4943-a0e6-4b8671851ef0) ![image](https://github.com/ripple/explorer/assets/8029314/a2d8c085-3b4e-4029-a76d-6ed046c6dac9) ## Test Plan Added tests. CI passes. Works locally.
- Loading branch information
Showing
15 changed files
with
779 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/containers/shared/components/Transaction/SetHook/Simple.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { useTranslation } from 'react-i18next' | ||
import { buildHookFlags } from '../../../transactionUtils' | ||
import { Account } from '../../Account' | ||
import { SimpleGroup } from '../SimpleGroup' | ||
import { SimpleRow } from '../SimpleRow' | ||
import { TransactionSimpleProps } from '../types' | ||
import { HookData, SetHookInstructions } from './types' | ||
import { hookOnToTxList } from './utils' | ||
|
||
export const Simple = ({ | ||
data, | ||
}: TransactionSimpleProps<SetHookInstructions>) => { | ||
const { hooks } = data.instructions | ||
const { t } = useTranslation() | ||
|
||
const renderHook = (hook: HookData) => ( | ||
<SimpleGroup title={t('hook')} key={hook.HookHash || hook.CreateCode}> | ||
<SimpleRow label={t('hash')} data-test="hook-hash"> | ||
{hook.HookHash ?? 'undefined'} | ||
</SimpleRow> | ||
{hook.HookOn && ( | ||
<SimpleRow label={t('triggered_on')} data-test="hook-on"> | ||
{/* // TODO: use the transaction badges here instead of just text */} | ||
{hookOnToTxList(hook.HookOn)?.join(', ') ?? <em>None</em>} | ||
</SimpleRow> | ||
)} | ||
{hook.HookGrants && ( | ||
<SimpleRow label={t('grant')} data-test="hook-grant"> | ||
{hook.HookGrants.map((hookGrant) => { | ||
const grant = hookGrant.HookGrant | ||
return ( | ||
<div className="grant" key={grant.HookHash}> | ||
<div className="hash">{grant.HookHash}</div> | ||
{grant.Authorize && <Account account={grant.Authorize} />} | ||
</div> | ||
) | ||
})} | ||
</SimpleRow> | ||
)} | ||
{hook.HookNamespace && ( | ||
<SimpleRow label={t('namespace')} data-test="hook-namespace"> | ||
{hook.HookNamespace} | ||
</SimpleRow> | ||
)} | ||
{hook.Flags && ( | ||
<SimpleRow label={t('flags')} data-test="hook-flags"> | ||
<em>{buildHookFlags(hook.Flags).join(', ')}</em> | ||
</SimpleRow> | ||
)} | ||
{hook.HookApiVersion != null && ( | ||
<SimpleRow label={t('api_version')} data-test="hook-api-version"> | ||
{hook.HookApiVersion} | ||
</SimpleRow> | ||
)} | ||
</SimpleGroup> | ||
) | ||
|
||
return <>{hooks.map(renderHook)}</> | ||
} |
15 changes: 15 additions & 0 deletions
15
src/containers/shared/components/Transaction/SetHook/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { | ||
TransactionAction, | ||
TransactionCategory, | ||
TransactionMapping, | ||
} from '../types' | ||
|
||
import { Simple } from './Simple' | ||
import { parser } from './parser' | ||
|
||
export const SetHookTransaction: TransactionMapping = { | ||
Simple, | ||
action: TransactionAction.CREATE, | ||
category: TransactionCategory.ACCOUNT, | ||
parser, | ||
} |
23 changes: 23 additions & 0 deletions
23
src/containers/shared/components/Transaction/SetHook/parser.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { SetHook, SetHookInstructions } from './types' | ||
|
||
export const parser = (tx: SetHook, meta: any): SetHookInstructions => { | ||
const hooks = tx.Hooks.map((hook) => hook.Hook) | ||
const affectedNodes = meta.AffectedNodes.filter( | ||
(node: any) => | ||
node.CreatedNode?.LedgerEntryType === 'Hook' || | ||
(node.ModifiedNode?.LedgerEntryType === 'Hook' && | ||
!!node.ModifiedNode?.PreviousFields?.Hooks), | ||
) | ||
const hashes = affectedNodes.flatMap((node: any) => | ||
(node.ModifiedNode?.FinalFields ?? node.CreatedNode?.NewFields)?.Hooks?.map( | ||
(hook: any) => hook.Hook.HookHash, | ||
), | ||
) | ||
// TODO: there may be bugs here when a `HookHash` is already specified in a hook | ||
// It's difficult to understand what situation that would be in, so this is left here for now | ||
hashes.forEach((element, index) => { | ||
if (hooks[index] != null) hooks[index].HookHash = element | ||
}) | ||
|
||
return { hooks: hooks.filter((hook) => hook.CreateCode || hook.HookHash) } | ||
} |
101 changes: 101 additions & 0 deletions
101
src/containers/shared/components/Transaction/SetHook/test/SetHookSimple.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { createSimpleWrapperFactory } from '../../test/createWrapperFactory' | ||
import { Simple } from '../Simple' | ||
import mockSetHook from './mock_data/SetHook.json' | ||
import mockSetHook2 from './mock_data/SetHook2.json' | ||
import mockSetHookFailure from './mock_data/SetHookFailure.json' | ||
import { expectSimpleRowText } from '../../test/expectations' | ||
|
||
const createWrapper = createSimpleWrapperFactory(Simple) | ||
|
||
describe('SetHookSimple', () => { | ||
it('renders', () => { | ||
const wrapper = createWrapper(mockSetHook) | ||
|
||
expect(wrapper.find('.group')).toHaveLength(2) | ||
|
||
const hook1 = wrapper.find('.group').at(0) | ||
const hook2 = wrapper.find('.group').at(1) | ||
|
||
expectSimpleRowText( | ||
hook1, | ||
'hook-hash', | ||
'4E57C7FE7A84ABFA53CFE411DE9BA3420B94F55038BF238EBE1EB89095ABA4DE', | ||
) | ||
expectSimpleRowText(hook1, 'hook-on', 'Invoke') | ||
expectSimpleRowText( | ||
hook1, | ||
'hook-namespace', | ||
'0000000000000000000000000000000000000000000000000000000000000000', | ||
) | ||
expectSimpleRowText(hook1, 'hook-flags', 'hsfOverride') | ||
expectSimpleRowText(hook1, 'hook-api-version', '0') | ||
|
||
expectSimpleRowText( | ||
hook2, | ||
'hook-hash', | ||
'C04E2043B656B578CB30E9FF465304AF402B7AFE38B6CE2D8CEFECDD669E3424', | ||
) | ||
expectSimpleRowText(hook2, 'hook-on', '98') | ||
expectSimpleRowText( | ||
hook2, | ||
'hook-namespace', | ||
'0000000000000000000000000000000000000000000000000000000000000000', | ||
) | ||
expectSimpleRowText(hook2, 'hook-flags', 'hsfOverride') | ||
expectSimpleRowText(hook2, 'hook-api-version', '0') | ||
}) | ||
|
||
it('renders a different SetHook tx', () => { | ||
const wrapper = createWrapper(mockSetHook2) | ||
|
||
expect(wrapper.find('.group')).toHaveLength(1) | ||
|
||
const hook = wrapper.find('.group').at(0) | ||
|
||
expectSimpleRowText( | ||
hook, | ||
'hook-hash', | ||
'548BBB700F5841C2D41E227456E8A80E6A6335D1149BA3B5FF745A00CC0EBECE', | ||
) | ||
|
||
expect(hook.find('.grant')).toHaveLength(2) | ||
|
||
const grant1 = hook.find('.grant').at(0) | ||
const grant2 = hook.find('.grant').at(1) | ||
|
||
expect(grant1.find('.hash')).toHaveText( | ||
'096A70632BBB67488F4804AE55604A01F52226BD556E3589270D0D30C9A6AF81', | ||
) | ||
expect(grant1.find('.account').at(0)).toHaveText( | ||
'rQUhXd7sopuga3taru3jfvc1BgVbscrb1X', | ||
) | ||
expect(grant1.find(`.account a`)).toExist() | ||
|
||
expect(grant2.find('.hash')).toHaveText( | ||
'3F47684053E1A653E54EAC1C5F50BCBAF7F69078CEFB5846BB046CE44B8ECDC2', | ||
) | ||
expect(grant2.find('.account').at(0)).toHaveText( | ||
'raPSFU999HcwpyRojdNh2i96T22gY9fgxL', | ||
) | ||
expect(grant2.find(`.account a`)).toExist() | ||
}) | ||
|
||
it('renders a failed SetHook tx', () => { | ||
const wrapper = createWrapper(mockSetHookFailure) | ||
|
||
expect(wrapper.find('.group')).toHaveLength(1) | ||
|
||
const hook = wrapper.find('.group').at(0) | ||
|
||
expectSimpleRowText(hook, 'hook-hash', 'undefined') | ||
|
||
expectSimpleRowText(hook, 'hook-on', 'Payment') | ||
expectSimpleRowText( | ||
hook, | ||
'hook-namespace', | ||
'CAE662172FD450BB0CD710A769079C05BFC5D8E35EFA6576EDC7D0377AFDD4A2', | ||
) | ||
expectSimpleRowText(hook, 'hook-flags', 'hsfOverride') | ||
expectSimpleRowText(hook, 'hook-api-version', '0') | ||
}) | ||
}) |
201 changes: 201 additions & 0 deletions
201
src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook.json
Large diffs are not rendered by default.
Oops, something went wrong.
127 changes: 127 additions & 0 deletions
127
src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook2.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
{ | ||
"tx": { | ||
"Account": "rGVHr1PrfL93UAjyw3DWZoi9adz2sLp2yL", | ||
"Fee": "20", | ||
"Flags": 0, | ||
"Hooks": [ | ||
{ | ||
"Hook": { | ||
"HookGrants": [ | ||
{ | ||
"HookGrant": { | ||
"Authorize": "rQUhXd7sopuga3taru3jfvc1BgVbscrb1X", | ||
"HookHash": "096A70632BBB67488F4804AE55604A01F52226BD556E3589270D0D30C9A6AF81" | ||
} | ||
}, | ||
{ | ||
"HookGrant": { | ||
"Authorize": "raPSFU999HcwpyRojdNh2i96T22gY9fgxL", | ||
"HookHash": "3F47684053E1A653E54EAC1C5F50BCBAF7F69078CEFB5846BB046CE44B8ECDC2" | ||
} | ||
} | ||
], | ||
"HookHash": "548BBB700F5841C2D41E227456E8A80E6A6335D1149BA3B5FF745A00CC0EBECE" | ||
} | ||
} | ||
], | ||
"LastLedgerSequence": 1976819, | ||
"NetworkID": 21338, | ||
"Sequence": 1784919, | ||
"SigningPubKey": "025137610C314DA06E4CD804541F2A7CDD0483EB85BA3F74067A026B5F170C8047", | ||
"TransactionType": "SetHook", | ||
"TxnSignature": "30450221008A7DD8DE50A7D107CF36DEA92D06B64926E865EADA243F18901DD7D9FB9D450D02203505F2C40D516D9208DF3172B6A45CB74C8DB0C18260C180B3185C7C872E0BAE", | ||
"ctid": "C01E29E10000535A", | ||
"date": 1680842731000 | ||
}, | ||
"meta": { | ||
"AffectedNodes": [ | ||
{ | ||
"ModifiedNode": { | ||
"FinalFields": { | ||
"Account": "rGVHr1PrfL93UAjyw3DWZoi9adz2sLp2yL", | ||
"Flags": 0, | ||
"Hooks": [ | ||
{ | ||
"Hook": { | ||
"HookGrants": [ | ||
{ | ||
"HookGrant": { | ||
"Authorize": "rQUhXd7sopuga3taru3jfvc1BgVbscrb1X", | ||
"HookHash": "096A70632BBB67488F4804AE55604A01F52226BD556E3589270D0D30C9A6AF81" | ||
} | ||
}, | ||
{ | ||
"HookGrant": { | ||
"Authorize": "raPSFU999HcwpyRojdNh2i96T22gY9fgxL", | ||
"HookHash": "3F47684053E1A653E54EAC1C5F50BCBAF7F69078CEFB5846BB046CE44B8ECDC2" | ||
} | ||
} | ||
], | ||
"HookHash": "548BBB700F5841C2D41E227456E8A80E6A6335D1149BA3B5FF745A00CC0EBECE" | ||
} | ||
}, | ||
{ | ||
"Hook": {} | ||
}, | ||
{ | ||
"Hook": {} | ||
}, | ||
{ | ||
"Hook": {} | ||
} | ||
], | ||
"OwnerNode": "0" | ||
}, | ||
"LedgerEntryType": "Hook", | ||
"LedgerIndex": "0BCDDA47012D784783CE787017E103BA542DFC451168074C9AA4704016893ED4", | ||
"PreviousFields": { | ||
"Hooks": [ | ||
{ | ||
"Hook": { | ||
"Flags": 0, | ||
"HookHash": "548BBB700F5841C2D41E227456E8A80E6A6335D1149BA3B5FF745A00CC0EBECE" | ||
} | ||
}, | ||
{ | ||
"Hook": {} | ||
}, | ||
{ | ||
"Hook": {} | ||
}, | ||
{ | ||
"Hook": {} | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
{ | ||
"ModifiedNode": { | ||
"FinalFields": { | ||
"Account": "rGVHr1PrfL93UAjyw3DWZoi9adz2sLp2yL", | ||
"Balance": "9879550122", | ||
"Flags": 0, | ||
"HookNamespaces": [ | ||
"01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0" | ||
], | ||
"HookStateCount": 74, | ||
"OwnerCount": 78, | ||
"Sequence": 1784920 | ||
}, | ||
"LedgerEntryType": "AccountRoot", | ||
"LedgerIndex": "BB71F3181F2B9D63FF4D7439AB82C32ABE4ED8F70CE00E0EFC68FD9C37149435", | ||
"PreviousFields": { | ||
"Balance": "9879550142", | ||
"OwnerCount": 76, | ||
"Sequence": 1784919 | ||
} | ||
} | ||
} | ||
], | ||
"TransactionIndex": 0, | ||
"TransactionResult": "tesSUCCESS" | ||
}, | ||
"hash": "62A6257455F2366CC54DE43EE40258E51FD1695459521D48DE70ECB4D53D677E", | ||
"ledger_index": 1976801, | ||
"date": 1680842731000 | ||
} |
Oops, something went wrong.