From 8aa684f1cc8ba1161f4d89fc595a41de257688ff Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 18 Jul 2023 12:46:30 -0400 Subject: [PATCH] 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. --- public/locales/en-US/translations.json | 8 +- src/containers/Transactions/simpleTab.scss | 9 + .../components/Transaction/SetHook/Simple.tsx | 59 +++++ .../components/Transaction/SetHook/index.ts | 15 ++ .../components/Transaction/SetHook/parser.ts | 23 ++ .../SetHook/test/SetHookSimple.test.tsx | 101 +++++++++ .../SetHook/test/mock_data/SetHook.json | 201 ++++++++++++++++++ .../SetHook/test/mock_data/SetHook2.json | 127 +++++++++++ .../test/mock_data/SetHookFailure.json | 53 +++++ .../Transaction/SetHook/test/utils.test.ts | 28 +++ .../components/Transaction/SetHook/types.ts | 37 ++++ .../components/Transaction/SetHook/utils.ts | 83 ++++++++ .../shared/components/Transaction/index.ts | 2 + .../Transaction/test/DefaultSimple.test.tsx | 10 +- src/containers/shared/transactionUtils.ts | 29 ++- 15 files changed, 779 insertions(+), 6 deletions(-) create mode 100644 src/containers/shared/components/Transaction/SetHook/Simple.tsx create mode 100644 src/containers/shared/components/Transaction/SetHook/index.ts create mode 100644 src/containers/shared/components/Transaction/SetHook/parser.ts create mode 100644 src/containers/shared/components/Transaction/SetHook/test/SetHookSimple.test.tsx create mode 100644 src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook.json create mode 100644 src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook2.json create mode 100644 src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHookFailure.json create mode 100644 src/containers/shared/components/Transaction/SetHook/test/utils.test.ts create mode 100644 src/containers/shared/components/Transaction/SetHook/types.ts create mode 100644 src/containers/shared/components/Transaction/SetHook/utils.ts diff --git a/public/locales/en-US/translations.json b/public/locales/en-US/translations.json index 13f36b4c5..8d65cc675 100644 --- a/public/locales/en-US/translations.json +++ b/public/locales/en-US/translations.json @@ -169,6 +169,7 @@ "transaction_type_name_PaymentChannelClaim": "Payment Channel Claim", "transaction_type_name_PaymentChannelCreate": "Payment Channel Create", "transaction_type_name_PaymentChannelFund": "Payment Channel Fund", + "transaction_type_name_SetHook": "Set Hook", "transaction_type_name_SetRegularKey": "Set Regular Key", "transaction_type_name_SignerListSet": "Signer List Set", "transaction_type_name_TicketCreate": "Ticket Create", @@ -472,5 +473,10 @@ "hook_exec_hash": "It triggered the hook <0>{{hash}}", "hook_exec_account": "On the account <0>{{account}}", "hook_exec_return": "Returned the code <0>{{code}} with string \"<1>{{string}}\"", - "hook_exec_emit_count": "Emitted <0>{{count}} transactions" + "hook_exec_emit_count": "Emitted <0>{{count}} transactions", + "hash": "Hash", + "grant": "Grant", + "namespace": "Namespace", + "api_version": "API Version", + "triggered_on": "Triggered On" } diff --git a/src/containers/Transactions/simpleTab.scss b/src/containers/Transactions/simpleTab.scss index 2337d28ed..297770905 100644 --- a/src/containers/Transactions/simpleTab.scss +++ b/src/containers/Transactions/simpleTab.scss @@ -26,6 +26,15 @@ $subdued-color: $black-40; .value { text-align: right; + .grant { + .account { + padding-bottom: 8px; + font-size: 11px; + text-align: right; + @include medium; + } + } + .amount { text-align: right; diff --git a/src/containers/shared/components/Transaction/SetHook/Simple.tsx b/src/containers/shared/components/Transaction/SetHook/Simple.tsx new file mode 100644 index 000000000..0e69821f8 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/Simple.tsx @@ -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) => { + const { hooks } = data.instructions + const { t } = useTranslation() + + const renderHook = (hook: HookData) => ( + + + {hook.HookHash ?? 'undefined'} + + {hook.HookOn && ( + + {/* // TODO: use the transaction badges here instead of just text */} + {hookOnToTxList(hook.HookOn)?.join(', ') ?? None} + + )} + {hook.HookGrants && ( + + {hook.HookGrants.map((hookGrant) => { + const grant = hookGrant.HookGrant + return ( +
+
{grant.HookHash}
+ {grant.Authorize && } +
+ ) + })} +
+ )} + {hook.HookNamespace && ( + + {hook.HookNamespace} + + )} + {hook.Flags && ( + + {buildHookFlags(hook.Flags).join(', ')} + + )} + {hook.HookApiVersion != null && ( + + {hook.HookApiVersion} + + )} +
+ ) + + return <>{hooks.map(renderHook)} +} diff --git a/src/containers/shared/components/Transaction/SetHook/index.ts b/src/containers/shared/components/Transaction/SetHook/index.ts new file mode 100644 index 000000000..6e836d117 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/index.ts @@ -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, +} diff --git a/src/containers/shared/components/Transaction/SetHook/parser.ts b/src/containers/shared/components/Transaction/SetHook/parser.ts new file mode 100644 index 000000000..9761f7c78 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/parser.ts @@ -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) } +} diff --git a/src/containers/shared/components/Transaction/SetHook/test/SetHookSimple.test.tsx b/src/containers/shared/components/Transaction/SetHook/test/SetHookSimple.test.tsx new file mode 100644 index 000000000..164d6a026 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/test/SetHookSimple.test.tsx @@ -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') + }) +}) diff --git a/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook.json b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook.json new file mode 100644 index 000000000..a220447a3 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook.json @@ -0,0 +1,201 @@ +{ + "tx": { + "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "Fee": "7644020", + "Flags": 0, + "Hooks": [ + { + "Hook": { + "CreateCode": "0061736D0100000001420960027F7F017F60037F7F7F017E60037F7F7E017E60027F7F017E60047F7F7F7F017E60017F017E6000017E60057F7F7F7F7F017E60097F7F7F7F7F7F7F7F7F017E02BC021403656E76025F67000003656E760A6F74786E5F6669656C64000103656E7606616363657074000203656E7608726F6C6C6261636B000203656E760C686F6F6B5F6163636F756E74000303656E76057374617465000403656E760974726163655F6E756D000203656E760C6574786E5F72657365727665000503656E760973746174655F736574000403656E760A6C65646765725F736571000603656E760C6574786E5F64657461696C73000303656E760D6574786E5F6665655F62617365000303656E7604656D6974000403656E76096F74786E5F736C6F74000503656E760D736C6F745F7375626669656C64000103656E760D736C6F745F7375626172726179000103656E7604736C6F74000103656E76057472616365000703656E760B7574696C5F6B65796C6574000803656E7608736C6F745F7365740001030201050503010002063F0A7F0141F08A040B7F0041EC0A0B7F004180080B7F0041F08A040B7F004180080B7F0041B0090B7F0041D0090B7F0041A0090B7F004180080B7F0041F0090B07080104686F6F6B00140AB6D20001B2D20002047F017E230041B0186B22012400200120003602A41841012200200010001A2001200141A2186A410241828004100137039818200120012D00A31820012D00A2184110746A3602941820012802941841E30047044041002200200042CC0010021A0B41BC094114418180201001421452044041002200200042CF0010031A0B20014180186A411410041A200141002200200041D009412010053703F81741900A410C20012903F81710061A20012903F817427B510440410510071A200141053A00F717200141F7176A410141D009412010085004404100200042E20010031A0B41D00941FF013A000041A009410841D009412010085004404100200042E60010031A0B41D00941003A0000200141003602F017034041E980808078410610001A024020012802F01741054F0D0041EF0920012802F01741016A3A000020012802F017410574418C086A411441D00941201008421452044041002200200042F00010031A0B41EF09410120012802F0174105744180086A41201008420152044041002200200042F40010031A0B2001200141F0156A22003602EC1520014280C0F4C198AF0B3703C8152001410022023602C415200120023602C015200110093E02BC15200141D0156A411410041A200141003A00BB1520012802EC1541123A000020012802EC1520012D00BB154108763A000120012802EC1520012D00BB153A0002200120012802EC1541036A3602EC1520014180808080783602B415200141023A00B31520012802EC1520012D00B315410F7141206A3A000020012802EC1520012802B4154118763A000120012802EC1520012802B4154110763A000220012802EC1520012802B4154108763A000320012802EC1520012802B4153A0004200120012802EC1541056A3602EC15200120012802C0153602AC152001410322033A00AB1520012802EC1520012D00AB15410F7141206A3A000020012802EC1520012802AC154118763A000120012802EC1520012802AC154110763A000220012802EC1520012802AC154108763A000320012802EC1520012802AC153A0004200120012802EC1541056A3602EC15200120023602A415200141043A00A31520012802EC1520012D00A315410F7141206A3A000020012802EC1520012802A4154118763A000120012802EC1520012802A4154110763A000220012802EC1520012802A4154108763A000320012802EC1520012802A4153A0004200120012802EC1541056A3602EC15200120012802C41536029C152001410E3A009B1520012802EC1520012D009B15410F7141206A3A000020012802EC15200128029C154118763A000120012802EC15200128029C154110763A000220012802EC15200128029C154108763A000320012802EC15200128029C153A0004200120012802EC1541056A3602EC15200120012802BC1541016A360294152001411A3A00931520012802EC15412022023A000020012802EC1520012D0093153A000120012802EC152001280294154118763A000220012802EC152001280294154110763A000320012802EC152001280294154108763A000420012802EC152001280294153A0005200120012802EC1541066A3602EC15200120012802BC1541056A36028C152001411B3A008B1520012802EC1520023A000020012802EC1520012D008B153A000120012802EC15200128028C154118763A000220012802EC15200128028C154110763A000320012802EC15200128028C154108763A000420012802EC15200128028C153A0005200120012802EC1541066A3602EC152001410122023A008A15200120012903C8153703801520012802EC1520012D008A15410F7141E0006A3A000020012802EC15200129038015423888423F8342407D3C000120012802EC1520012903801542308842FF01833C000220012802EC1520012903801542288842FF01833C000320012802EC1520012903801542208842FF01833C000420012802EC1520012903801542188842FF01833C000520012802EC1520012903801542108842FF01833C000620012802EC1520012903801542088842FF01833C000720012802EC1520012903801542FF01833C0008200120012802EC1541096A3602EC15200120012802EC153602FC142001410822043A00FB14200142003703F01420012802EC1520012D00FB14410F7141E0006A3A000020012802EC1520012903F014423888423F8342407D3C000120012802EC1520012903F01442308842FF01833C000220012802EC1520012903F01442288842FF01833C000320012802EC1520012903F01442208842FF01833C000420012802EC1520012903F01442188842FF01833C000520012802EC1520012903F01442108842FF01833C000620012802EC1520012903F01442088842FF01833C000720012802EC1520012903F01442FF01833C0008200120012802EC1541096A3602EC1520012802EC1541F3003A000020012802EC1541213A000120012802EC15200537030220012802EC15200537030A20012802EC15200537031220012802EC152005370319200120012802EC1541236A3602EC15200120023A00EF1420012802EC1520012D00EF144180016A3A000020012802EC15411422023A000120012802EC1520012903D01537030220012802EC1520012903D81537030A20012802EC1520012802E015360212200120012802EC1541166A3602EC15200120033A00EE1420012802EC1520012D00EE144180016A3A000020012802EC1520023A000120012802EC1520012802F01741057429038C0837030220012802EC1520012802F0174105742903940837030A20012802EC1520012802F01741057428029C08360212200120012802EC1541166A3602EC15200120012802EC1541F8012202100A3703E014200120002002100B3703D814200120043A00D714200120012903D8143703C81420012802FC1420012D00D714410F7141E0006A3A000020012802FC1420012903C814423888423F8342407D3C000120012802FC1420012903C81442308842FF01833C000220012802FC1420012903C81442288842FF01833C000320012802FC1420012903C81442208842FF01833C000420012802FC1420012903C81442188842FF01833C000520012802FC1420012903C81442108842FF01833C000620012802FC1420012903C81442088842FF01833C000720012802FC1420012903C81442FF01833C0008200120012802FC1441096A3602FC142001200141A0146A412020002002100C37039814200520012903981459044041002200200042FD0010031A0B419D0A410B20012903981410061A200120012802F01741016A3602F0170C010B0B41002200200042820110021A0B024020012903801841BC09290300520D0020012903881841C409290300520D0020012802901841CC09280200470D004100200042890110021A0B20014100200041B009412010053703901420012903901442005304404100200042920110031A0B4101100D42015204404100200042960110031A0B41014193803C4102100E42025204404100200042970110031A0B4102220041002000100F420252044041002200200042990110031A0B41024198801C4103100E4203520440410022002000429A0110031A0B41024199801C4104100E4204520440410022002000429B0110031A0B2001200141900C6A2200418008410410103703880C41A90A41052202200020012903880CA7410110111A20014100220020004103101042FF01833703800C41AE0A200220012903800C10061A024020012903800C420159044020012903800C4219570D010B4100200042A40110031A0B2001200141DC0B6A3602CC0B2001027F410820012903800C4201510D001A4120411420012903800C420259047F20012903800C4205570520000B4101711B0B3A00CB0B41B00920012903800C3C000020012802CC0B41016B20012D00CB0B41016A4104101020012D00CB0B41016AAC5204404100200042B10110031A0B20012802CC0B41016B41003A00002001200141A00B6A20012D00CB0B41B00922004120220210053703980B20012802CC0B20012D00CB0B20002002100820012D00CB0BAD52044041002200200042BA0110031A0B024020012903980B20012D00CB0BAD520D0020012903A00B20012802CC0B290300520D0020012903A80B20012802CC0B290308520D0020012903B00B20012802CC0B290310520D0020012903B80B20012802CC0B290318520D0020012903C00B20012802CC0B290320520D0020012903C80B20012802CC0B290328520D0020012903D00B20012802CC0B290330520D0020012903D80B20012802CC0B290338520D0041002200200042BF0110021A0B20012903980B4200550440200141003A00970B200120012903800C3C00BF0B0240200141970B6A4101200141A00B6A41201005500D0020012D00970B450D00200120012D00970B41016B3A00970B200141970B6A4101200141A00B6A4120100850044041002200200042CF0110031A0B0B0B200141003A00960B200120012802CC0B2D001F3A00950B20012802CC0B20012903800C3C001F200141960B6A4101220020012802CC0B412010051A200120012D00960B20006A3A00960B200141960B6A410120012802CC0B4120100850044041002200200042DB0110031A0B20012802CC0B20012D00950B3A001F2001027F410020012802CC0B29030041F009290300520D001A410020012802CC0B29030841F809290300520D001A410020012802CC0B29031041800A290300520D001A410020012802CC0B29031841880A290300520D001A410020012802CC0B29032041900A290300520D001A410020012802CC0B29032841980A290300520D001A410020012802CC0B29033041A00A290300520D001A20012802CC0B29033841A80A290300510B4101713602900B41B40A410F20012802900BAC10061A41C40A4105220020012D00960BAD10061A41900A410C20012903F81710061A41AE0A200020012903800C10061A024020012903F81720012D00960BAD52044020012903800C4205570D0120012D00960BB720012903F817B9449A9999999999E93FA266450D010B41CA0A411141DC0A4110410010111A024020012903800C420151044041D00941FF013A000020012802CC0B410841D0094120100850044041002200200042F40110031A0B0C010B024020012903800C4205570440200120012903800C42027D3C008F0B200141E00A6A4122410120014180186A411441002200200020002000101242225204404100200042FD0110031A0B200141E00A6A41224105101342055204404100200042FE0110031A0B4105418B803C4106100E42065204404100200042810210031A0B410620012D008F0B4107100F42075104404107419F80144108100E42085204404100200042890210031A0B200141C00A6A412041081010422052044041002000428A0210031A0B024020012903C00A20012802CC0B290300520D0020012903C80A20012802CC0B290308520D0020012903D00A20012802CC0B290310520D0020012903D80A20012802CC0B290318520D0020012903E00A20012802CC0B290320520D0020012903E80A20012802CC0B290328520D0020012903F00A20012802CC0B290330520D0020012903F80A20012802CC0B290338520D0041002000428E0210021A0B0B200141E00A6A4122411820012802CC0B41204100200020002000101242225204404100200042920210031A0B200141E00A6A41224109101342095204404100200042950210031A0B410110071A200141A00A6A21022001027F417F20012802900B0D001A20012802CC0B0B3602BC0A2002027F20012D008F0B45044020012802BC0A0C010B41000B360200200241046A2200027F20012D008F0B410146044020012802BC0A0C010B41000B360200200041046A2200027F20012D008F0B410246044020012802BC0A0C010B41000B360200200041046A027F20012D008F0B410346044020012802BC0A0C010B41000B36020020014100220036029C022001200141A0026A220236029802200110093E02FC0120014180026A411410041A200141163A00FB0120012802980241123A000020012802980220012D00FB014108763A000120012802980220012D00FB013A0002200120012802980241036A3602980220014180808080783602F401200141023A00F30120012802980220012D00F301410F7141206A3A000020012802980220012802F4014118763A000120012802980220012802F4014110763A000220012802980220012802F4014108763A000320012802980220012802F4013A0004200120012802980241056A36029802200120003602EC01200141043A00EB0120012802980220012D00EB01410F7141206A3A000020012802980220012802EC014118763A000120012802980220012802EC014110763A000220012802980220012802EC014108763A000320012802980220012802EC013A0004200120012802980241056A36029802200120012802FC0141016A3602E4012001411A3A00E301200128029802412022033A000020012802980220012D00E3013A000120012802980220012802E4014118763A000220012802980220012802E4014110763A000320012802980220012802E4014108763A000420012802980220012802E4013A0005200120012802980241066A36029802200120012802FC0141056A3602DC012001411B3A00DB0120012802980220033A000020012802980220012D00DB013A000120012802980220012802DC014118763A000220012802980220012802DC014110763A000320012802980220012802DC014108763A000420012802980220012802DC013A0005200120012802980241066A3602980220012001280298023602D401200141083A00D301200142003703C80120012802980220012D00D301410F7141E0006A3A000020012802980220012903C801423888423F8342407D3C000120012802980220012903C80142308842FF01833C000220012802980220012903C80142288842FF01833C000320012802980220012903C80142208842FF01833C000420012802980220012903C80142188842FF01833C000520012802980220012903C80142108842FF01833C000620012802980220012903C80142088842FF01833C000720012802980220012903C80142FF01833C0008200120012802980241096A3602980220012802980241F3003A000020012802980241213A00012001280298022005370302200128029802200537030A20012802980220053703122001280298022005370319200120012802980241236A36029802200141013A00C70120012802980220012D00C7014180016A3A000020012802980241143A000120012802980220012903800237030220012802980220012903880237030A200128029802200128029002360212200120012802980241166A36029802200141800820012802980220026B6B3602C001200120012802980220012802C001100A3703B801200120012802980220012903B801A76A360298022001200128029802220241016A36029802200241FB013A0000200120012802A00A3602B4012001200128029802220241016A36029802200241EE013A0000200020012802B4014704402001200128029802220041016A36029802200041223A00002001200128029802220041016A360298022000410022003A00002001200128029802220241016A36029802200220003A00002001200128029802220241016A36029802200220003A00002001200128029802220041016A36029802200041013A0000024020012802B401417F4604402001200128029802220041016A36029802200041FB003A00002001200128029802220041016A36029802200041003A00000C010B2001200128029802220041016A360298022000411F3A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A0000200120012802B401220041016A3602B40120002D000021002001200128029802220241016A36029802200220003A00000B0B2001200128029802220041016A36029802200041E1013A0000200120012802A40A3602B0012001200128029802220041016A36029802200041EE013A000020012802B00104402001200128029802220041016A36029802200041223A00002001200128029802220041016A360298022000410022003A00002001200128029802220241016A36029802200220003A00002001200128029802220241016A36029802200220003A00002001200128029802220041016A36029802200041013A0000024020012802B001417F4604402001200128029802220041016A36029802200041FB003A00002001200128029802220041016A36029802200041003A00000C010B2001200128029802220041016A360298022000411F3A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A0000200120012802B001220041016A3602B00120002D000021002001200128029802220241016A36029802200220003A00000B0B2001200128029802220041016A36029802200041E1013A0000200120012802A80A3602AC012001200128029802220041016A36029802200041EE013A000020012802AC0104402001200128029802220041016A36029802200041223A00002001200128029802220041016A360298022000410022003A00002001200128029802220241016A36029802200220003A00002001200128029802220241016A36029802200220003A00002001200128029802220041016A36029802200041013A0000024020012802AC01417F4604402001200128029802220041016A36029802200041FB003A00002001200128029802220041016A36029802200041003A00000C010B2001200128029802220041016A360298022000411F3A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A0000200120012802AC01220041016A3602AC0120002D000021002001200128029802220241016A36029802200220003A00000B0B2001200128029802220041016A36029802200041E1013A0000200120012802AC0A3602A8012001200128029802220041016A36029802200041EE013A000020012802A80104402001200128029802220041016A36029802200041223A00002001200128029802220041016A360298022000410022003A00002001200128029802220241016A36029802200220003A00002001200128029802220241016A36029802200220003A00002001200128029802220041016A36029802200041013A0000024020012802A801417F4604402001200128029802220041016A36029802200041FB003A00002001200128029802220041016A36029802200041003A00000C010B2001200128029802220041016A360298022000411F3A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A0000200120012802A801220041016A3602A80120002D000021002001200128029802220241016A36029802200220003A00000B0B2001200128029802220041016A36029802200041E1013A00002001200128029802220041016A36029802200041F1013A00002001200128029802200141A0026A22006B36029C0220012000200128029C02100B3703A001200141083A009F01200120012903A0013703900120012802D40120012D009F01410F7141E0006A3A000020012802D401200129039001423888423F8342407D3C000120012802D40120012903900142308842FF01833C000220012802D40120012903900142288842FF01833C000320012802D40120012903900142208842FF01833C000420012802D40120012903900142188842FF01833C000520012802D40120012903900142108842FF01833C000620012802D40120012903900142088842FF01833C000720012802D40120012903900142FF01833C0008200120012802D40141096A3602D4012001200141F0006A41202000200128029C02100C370368419D0A410B200129036810061A0C010B41EF0920012903800C42067D3C00002001200141CC006A411441D0094120100542145136023C02400240200128023C450D0020012802900B0D000C010B20012903F817420057044041002200200042C20210031A0B0240200128023C0440200120012903F81742017D3703F8170C010B200120012903F81742017C3703F8170B200141F8176A410141F00941201008420152044041002200200042C90210031A0B0B200128023C044020014101360238034041CF82808078411A10001A0240200128023841194A0D00200120012802383A0040200141106A41202200200141406B200010054220510440200141003A000F2001410F6A4101200141106A412010054201510440024020012D000F41014D0440410022002000200141106A41201008504504404100200042DA0210031A0B0C010B200120012D000F41016B3A000F2001410F6A4101200141106A41201008420152044041002200200042DF0210031A0B0B0B410022002000200141406B41201008504504404100200042E40210031A0B0B2001200128023841016A3602380C010B0B0B20012802900B45044041EF0920012903800C42067D3C000020012802CC0B411441D00941201008421452044041002200200042EE0210031A0B41EF094101200141D00B6A41201008421452044041002200200042F10210031A0B0B0B0B0B41002200200042F80210021A20012903A8182105200141B0186A240020050B0BEC010600418C080B14C2F107E6E864D3906D0A088446FDDF8A7B2F569C0041AC080B149EEA73F5F0627E69397EC72E9A3C7804C0F2BF690041CC080B14C3E8E29AB62847275CED36EBF4E928DC25A07F240041EC080B14B7DA762DB9902E85199666B2E6C3009C5E27576900418C090B1CD70EF4D5021C7C646A98E84F60FED364A004453253CBD7A6250D78800041900A0B5B6D656D6265725F636F756E7400656D69745F726573756C740064756D7000746F70696300746F7069635F646174615F7A65726F00766F7465730022416374696F6E696E6720766F7465732200416374696F6E696E6720766F746573", + "Flags": 1, + "HookApiVersion": 0, + "HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFF", + "HookHash": "4E57C7FE7A84ABFA53CFE411DE9BA3420B94F55038BF238EBE1EB89095ABA4DE" + } + }, + { + "Hook": { + "CreateCode": "0061736D0100000001530C60017F017E60027F7F017F60037F7F7F017E60037F7F7E017E60027F7F017E60097F7F7F7F7F7F7F7F7F017E6000017E60047F7F7F7F017E60037E7E7F017E60027F7E017E60027E7E017E60037E7F7F017E02FF021703656E760C6574786E5F72657365727665000003656E76025F67000103656E760A6F74786E5F6669656C64000203656E7606616363657074000303656E760C686F6F6B5F6163636F756E74000403656E760B7574696C5F6B65796C6574000503656E7608736C6F745F736574000203656E760D736C6F745F7375626669656C64000203656E7604736C6F74000203656E76106C65646765725F6C6173745F74696D65000603656E7608726F6C6C6261636B000303656E760974726163655F6E756D000303656E760A6C65646765725F736571000603656E76057374617465000703656E760D666C6F61745F636F6D70617265000803656E7609666C6F61745F6F6E65000603656E7609666C6F61745F736574000903656E760C666C6F61745F646976696465000A03656E760E666C6F61745F6D756C7469706C79000A03656E7609666C6F61745F696E74000B03656E760C6574786E5F64657461696C73000403656E760D6574786E5F6665655F62617365000403656E7604656D697400070302010005030100020621057F0141A08A040B7F00419D0A0B7F004180080B7F0041A08A040B7F004180080B07080104686F6F6B00170AF0980001EC980002047F017E230041A0066B2201240020012000360294064101220010001A2000200010011A200120014180066A41104182800410023703F805200120012D00810620012D0080064110746A3602F40520012802F40541E200470440418008411E421810031A0B200141E0056A411422004181802010021A200141C0056A200010041A024020012903C00520012903E005520D0020012903C80520012903E805520D0020012802D00520012802F005470D00419E08411D422210031A0B20014190056A2202412222034103200141E0056A41144100220020002000200010051A200220034101220010061A200041E4800C41021007420252044041BB084121422D10031A0B410141E38008410310071A200041E48008410410071A200041828018410510071A200041E280084106220010071A20014100220220022000100837038805200110092001290388057D37038005200129038005423C530440200141E0046A220041166A41002901F608370100200041106A20022903F008370300200041086A20022903E808370300200020022903E0083703002001423C2001290380057D37038005200120012D00EE04AD20012903800542C0843D7F420A817C3C00EE04200120012D00EF04AD20012903800542A08D067F420A817C3C00EF04200120012D00F004AD2001290380054290CE007F420A817C3C00F004200120012D00F104AD20012903800542E8077F420A817C3C00F104200120012D00F204AD20012903800542E4007F420A817C3C00F204200120012D00F304AD200129038005420A7F420A817C3C00F304200120012D00F404AD200129038005420A817C3C00F4042000411E42C600100A1A0B2001410022002000410210083703D804200120002000410310083703D0042001200020004104220210083703C8042001200020004105220010083703C00441FE08410B20012903D804100B1A418A09200020012903D004100B1A419009200220012903C804100B1A024020012903D004420055044020012903C8044200550D010B419509411B42D500100A1A0B2001100C3703B804200120012903B80420012903D0047D3703B00420012903B0044200570440419509411B42DD00100A1A0B2001100C20012903C8047D3703A804200120012903C00442FFFFFFFFFFFFFFFF1F833703C004200120012903C00442C0843D7F3703C00441B009410320012903C004100B1A41FE08410B20012903D804100B1A024020012903C0044200570D0020012903A8044200570D00200120012903D80420012903C00420012903A8047E7C3703D8040B41FE08410B20012903D804100B1A200141FF013A008004200141002200200020014180046A4120100D3703F8030240024020012903F8034200570D0020012903F80342004102100E2005520D0020012903F803100F4104100E500D010B200142D5AA81AAE2F4F5E5D3003703F8030B20012903F8034200570440419509411B42FB00100A1A0B2001410020012903D80410103703F00320012903F0034200570440419509411B42FF00100A1A0B2001410020012903B00410103703E80320012903E8034200570440419509411B428201100A1A0B200120012903F00320012903E80310113703E003200120012903F80320012903E00310123703E00341B409410A20012903E003100B1A200120012903E0034106410010133703D80341BF09410C20012903D803100B1A2001200141E0016A22023602DC01200120012903D8033703B801200120003602B401200120003602B0012001100C3E02AC01200141C0016A411410041A200141003A00AB0120012802DC0141123A000020012802DC0120012D00AB014108763A000120012802DC0120012D00AB013A0002200120012802DC0141036A3602DC0120014180808080783602A401200141023A00A30120012802DC0120012D00A301410F7141206A3A000020012802DC0120012802A4014118763A000120012802DC0120012802A4014110763A000220012802DC0120012802A4014108763A000320012802DC0120012802A4013A0004200120012802DC0141056A3602DC01200120012802B00136029C012001410322033A009B0120012802DC0120012D009B01410F7141206A3A000020012802DC01200128029C014118763A000120012802DC01200128029C014110763A000220012802DC01200128029C014108763A000320012802DC01200128029C013A0004200120012802DC0141056A3602DC012001200036029401200141043A00930120012802DC0120012D009301410F7141206A3A000020012802DC012001280294014118763A000120012802DC012001280294014110763A000220012802DC012001280294014108763A000320012802DC012001280294013A0004200120012802DC0141056A3602DC01200120012802B40136028C012001410E3A008B0120012802DC0120012D008B01410F7141206A3A000020012802DC01200128028C014118763A000120012802DC01200128028C014110763A000220012802DC01200128028C014108763A000320012802DC01200128028C013A0004200120012802DC0141056A3602DC01200120012802AC0141016A360284012001411A3A00830120012802DC01412022003A000020012802DC0120012D0083013A000120012802DC012001280284014118763A000220012802DC012001280284014110763A000320012802DC012001280284014108763A000420012802DC012001280284013A0005200120012802DC0141066A3602DC01200120012802AC0141056A36027C2001411B3A007B20012802DC0120003A000020012802DC0120012D007B3A000120012802DC01200128027C4118763A000220012802DC01200128027C4110763A000320012802DC01200128027C4108763A000420012802DC01200128027C3A0005200120012802DC0141066A3602DC012001410122003A007A200120012903B80137037020012802DC0120012D007A410F7141E0006A3A000020012802DC012001290370423888423F8342407D3C000120012802DC01200129037042308842FF01833C000220012802DC01200129037042288842FF01833C000320012802DC01200129037042208842FF01833C000420012802DC01200129037042188842FF01833C000520012802DC01200129037042108842FF01833C000620012802DC01200129037042088842FF01833C000720012802DC01200129037042FF01833C0008200120012802DC0141096A3602DC01200120012802DC0136026C2001410822043A006B2001420037036020012802DC0120012D006B410F7141E0006A3A000020012802DC012001290360423888423F8342407D3C000120012802DC01200129036042308842FF01833C000220012802DC01200129036042288842FF01833C000320012802DC01200129036042208842FF01833C000420012802DC01200129036042188842FF01833C000520012802DC01200129036042108842FF01833C000620012802DC01200129036042088842FF01833C000720012802DC01200129036042FF01833C0008200120012802DC0141096A3602DC0120012802DC0141F3003A000020012802DC0141213A000120012802DC01200537030220012802DC01200537030A20012802DC01200537031220012802DC012005370319200120012802DC0141236A3602DC01200120003A005F20012802DC0120012D005F4180016A3A000020012802DC01411422003A000120012802DC0120012903C00137030220012802DC0120012903C80137030A20012802DC0120012802D001360212200120012802DC0141166A3602DC01200120033A005E20012802DC0120012D005E4180016A3A000020012802DC0120003A000120012802DC0120012903E00537030220012802DC0120012903E80537030A20012802DC0120012802F005360212200120012802DC0141166A3602DC01200120012802DC0141F801220010143703502001200220001015370348200120043A004720012001290348370338200128026C20012D0047410F7141E0006A3A0000200128026C2001290338423888423F8342407D3C0001200128026C200129033842308842FF01833C0002200128026C200129033842288842FF01833C0003200128026C200129033842208842FF01833C0004200128026C200129033842188842FF01833C0005200128026C200129033842108842FF01833C0006200128026C200129033842088842FF01833C0007200128026C200129033842FF01833C00082001200128026C41096A36026C2001200141106A412020022000101637030841CC09410B2001290308100B1A2001290308200555044041D8094129429A0110031A0B41810A411C429E01100A1A2001290398062105200141A0066A240020050B0BA40201004180080B9C025265776172643A2050617373696E67206E6F6E2D636C61696D2074786E005265776172643A2050617373696E67206F7574676F696E672074786E005265776172643A2050617373696E67207265776172642073657475702074786E0000000000596F75206D75737420776169742030303030303030207365636F6E647300616363756D756C61746F72006669727374006C617374005265776172643A20417373657274696F6E206661696C7572652E0062616C0078666C5F726577617264007265776172645F64726F707300656D69745F726573756C74005265776172643A20456D6974746564207265776172642074786E207375636365737366756C6C792E005265776172643A20456D697420726577617264206661696C65642E", + "Flags": 1, + "HookApiVersion": 0, + "HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFBFFFFF", + "HookHash": "C04E2043B656B578CB30E9FF465304AF402B7AFE38B6CE2D8CEFECDD669E3424" + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + }, + { + "Hook": { + "CreateCode": "", + "Flags": 1 + } + } + ], + "LastLedgerSequence": 1955551, + "NetworkID": 21338, + "Sequence": 52, + "SigningPubKey": "03799CADC441958EF655C7CF893638E8DF9F157925C0AD98981DFC55BC323FCBCE", + "TransactionType": "SetHook", + "TxnSignature": "3045022100FD1802C00CBEBB5CEF19C30A0023EFE12C807413D946B8194583CC100F1D12D9022079D049CE87CBCA8D157F6D5E8C077BD14B8DEBFA7B40EC37E53D758A6906CC3D", + "ctid": "C01DD6CD0000535A", + "date": 1680778612000 + }, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "Balance": "1008078901610", + "Flags": 1114112, + "OwnerCount": 2, + "RegularKey": "rDADDYfnLvVY9FBnS8zFXhwYFHPuU5q2Sk", + "Sequence": 53 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8", + "PreviousFields": { + "Balance": "1008086545630", + "Sequence": 52 + } + } + }, + { + "ModifiedNode": { + "FinalFields": { + "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + "Flags": 0, + "Hooks": [ + { + "Hook": { + "Flags": 0, + "HookHash": "4E57C7FE7A84ABFA53CFE411DE9BA3420B94F55038BF238EBE1EB89095ABA4DE", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFFFFFFFFFBFFFFF" + } + }, + { + "Hook": { + "Flags": 0, + "HookHash": "C04E2043B656B578CB30E9FF465304AF402B7AFE38B6CE2D8CEFECDD669E3424", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFBFFFFF" + } + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + } + ], + "OwnerNode": "0" + }, + "LedgerEntryType": "Hook", + "LedgerIndex": "469372BEE8814EC52CA2AECB5374AB57A47B53627E3C0E2ACBE3FDC78DBFEC7B", + "PreviousFields": { + "Hooks": [ + { + "Hook": { + "HookHash": "4E57C7FE7A84ABFA53CFE411DE9BA3420B94F55038BF238EBE1EB89095ABA4DE" + } + }, + { + "Hook": { + "HookHash": "C04E2043B656B578CB30E9FF465304AF402B7AFE38B6CE2D8CEFECDD669E3424" + } + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + }, + { + "Hook": {} + } + ] + } + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tesSUCCESS" + }, + "hash": "12E9523791E48ABF1F8FF24771EF641F7E4BBE9D77BFA03AB1036517C041E569", + "ledger_index": 1955533, + "date": 1680778612000 +} diff --git a/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook2.json b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook2.json new file mode 100644 index 000000000..89c5a72c6 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHook2.json @@ -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 +} diff --git a/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHookFailure.json b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHookFailure.json new file mode 100644 index 000000000..2d0b20025 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/test/mock_data/SetHookFailure.json @@ -0,0 +1,53 @@ +{ + "tx": { + "Account": "rXKD82Qx77BCMVNgQYak5i5bh8KDXVfvm", + "Fee": "133020", + "Flags": 0, + "Hooks": [ + { + "Hook": { + "CreateCode": "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141C088040B7F004180080B7F0041B2080B7F004180080B7F0041C088040B7F0041000B7F0041010B07080104686F6F6B00030AC1800001BD800001017F230041106B220124002001200036020C41A00841114180084110410010001A4190084110420910011A4101410110021A200141106A240042000B0B3801004180080B31426173652E633A2043616C6C65642E00626173653A2046696E69736865642E0022426173652E633A2043616C6C65642E22", + "Flags": 1, + "HookApiVersion": 0, + "HookNamespace": "CAE662172FD450BB0CD710A769079C05BFC5D8E35EFA6576EDC7D0377AFDD4A2", + "HookOn": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFE" + } + } + ], + "LastLedgerSequence": 4597710, + "NetworkID": 21338, + "Sequence": 4398843, + "SigningPubKey": "032CDB60825AEE26E28B4BC916212BC206EF6992ED090728402554F6BEC3A169CF", + "TransactionType": "SetHook", + "TxnSignature": "304502210080A3AF02FC52935BFA746B374F38DBBF371DC69EC544A9230467993FA40384ED02205D544A5A4B924101C4F3E22CB89E95D21AC640DC8915C474AC046F4288F52B26", + "ctid": "C04627BC0000535A", + "date": 1688754701000 + }, + "meta": { + "AffectedNodes": [ + { + "ModifiedNode": { + "FinalFields": { + "Account": "rXKD82Qx77BCMVNgQYak5i5bh8KDXVfvm", + "Balance": "1199990", + "Flags": 0, + "ImportSequence": 39203734, + "OwnerCount": 0, + "Sequence": 4398844 + }, + "LedgerEntryType": "AccountRoot", + "LedgerIndex": "B0B02F51EDE6BD9F0D7247955474A5B28AB8F9683811AFB3E9AFEF162440C8C5", + "PreviousFields": { + "Balance": "1333010", + "Sequence": 4398843 + } + } + } + ], + "TransactionIndex": 0, + "TransactionResult": "tecINSUFFICIENT_RESERVE" + }, + "hash": "3015BB519D32BDD58CF2867E5F512A0D0532D9E9C93361EC51DA7C70B80549D3", + "ledger_index": 4597692, + "date": 1688754701000 +} diff --git a/src/containers/shared/components/Transaction/SetHook/test/utils.test.ts b/src/containers/shared/components/Transaction/SetHook/test/utils.test.ts new file mode 100644 index 000000000..c74bcd8e0 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/test/utils.test.ts @@ -0,0 +1,28 @@ +import { hookOnToTxList } from '../utils' + +describe('SetHook utils', () => { + it('hookOnToTxList', () => { + expect( + hookOnToTxList( + '0000000000000000000000000000000000000000000000000000000000000000', + ), + ).toEqual(['All transactions']) + expect( + hookOnToTxList( + '0xfffffffffffffffffffffffffffffffffffffff7ffffffffffffffffff9affeb', + ), + ).toEqual([ + 'Invoke', + 'AccountDelete', + 'CheckCancel', + 'CheckCreate', + 'EscrowCancel', + 'EscrowFinish', + ]) + expect( + hookOnToTxList( + '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff', + ), + ).toEqual(undefined) + }) +}) diff --git a/src/containers/shared/components/Transaction/SetHook/types.ts b/src/containers/shared/components/Transaction/SetHook/types.ts new file mode 100644 index 000000000..c89d314e4 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/types.ts @@ -0,0 +1,37 @@ +interface HookGrant { + HookGrant: { + HookHash: string + Authorize?: string + } +} + +interface HookParameter { + HookParameter: { + HookParameterName: string + HookParameterValue: string + } +} + +export interface HookData { + HookHash?: string + CreateCode?: string + Flags?: number + HookOn?: string + HookNamespace?: string + HookApiVersion?: number + HookParameters?: HookParameter[] + HookGrants?: HookGrant[] +} + +interface Hook { + Hook: HookData +} + +export interface SetHook { + TransactionType: 'SetHook' + Hooks: Hook[] +} + +export interface SetHookInstructions { + hooks: HookData[] +} diff --git a/src/containers/shared/components/Transaction/SetHook/utils.ts b/src/containers/shared/components/Transaction/SetHook/utils.ts new file mode 100644 index 000000000..31498f7b9 --- /dev/null +++ b/src/containers/shared/components/Transaction/SetHook/utils.ts @@ -0,0 +1,83 @@ +import { zeroPad } from '../../../transactionUtils' + +// TODO: import from ripple-binary-codec +const TRANSACTION_TYPES: Record = { + Invalid: -1, + Payment: 0, + EscrowCreate: 1, + EscrowFinish: 2, + AccountSet: 3, + EscrowCancel: 4, + SetRegularKey: 5, + NickNameSet: 6, + OfferCreate: 7, + OfferCancel: 8, + Contract: 9, + TicketCreate: 10, + TicketCancel: 11, + SignerListSet: 12, + PaymentChannelCreate: 13, + PaymentChannelFund: 14, + PaymentChannelClaim: 15, + CheckCreate: 16, + CheckCash: 17, + CheckCancel: 18, + DepositPreauth: 19, + TrustSet: 20, + AccountDelete: 21, + SetHook: 22, + NFTokenMint: 25, + NFTokenBurn: 26, + NFTokenCreateOffer: 27, + NFTokenCancelOffer: 28, + NFTokenAcceptOffer: 29, + Invoke: 99, + EnableAmendment: 100, + SetFee: 101, + UNLModify: 102, + EmitFailure: 103, +} + +const transactionMap = Object.entries(TRANSACTION_TYPES).reduce( + (flipped, [key, value]) => { + // eslint-disable-next-line no-param-reassign -- fine for a reduce + flipped[value] = key + return flipped + }, + {} as Record, +) + +const maxTransactionValue: number = 103 + +function hex2bin(input) { + const hex = input.replace('0x', '').toLowerCase() + let bin = '' + for (let i = 0; i < hex.length; i += 1) { + const binFragment = parseInt(hex[i], 16).toString(2) + bin += binFragment.padStart(4, '0') + } + return bin +} + +export function hookOnToTxList(hookOn?: string): string[] | undefined { + if (hookOn == null) return undefined + if ( + hookOn === + '0000000000000000000000000000000000000000000000000000000000000000' + ) + return ['All transactions'] + const bits = hex2bin(hookOn).split('') + + const txs = bits + .map((value, i) => { + const bin = zeroPad(1, 256 - i, true) + const int = Math.log2(parseInt(bin, 2)) + // const type = i < 8 ? 'universal' : (i < 16 ? 'type_specific' : 'reserved'); + const flagOn = int === 22 ? '1' : '0' + if (value === flagOn && int < maxTransactionValue) + return transactionMap[int] || int + return undefined + }) + .filter((d) => Boolean(d)) as string[] + return txs.length === 0 ? undefined : txs +} diff --git a/src/containers/shared/components/Transaction/index.ts b/src/containers/shared/components/Transaction/index.ts index e1e2b7b90..c6e2bdf9a 100644 --- a/src/containers/shared/components/Transaction/index.ts +++ b/src/containers/shared/components/Transaction/index.ts @@ -19,6 +19,7 @@ import { PaymentChannelClaimTransaction as PaymentChannelClaim } from './Payment import { PaymentChannelCreateTransaction as PaymentChannelCreate } from './PaymentChannelCreate' import { PaymentChannelFundTransaction as PaymentChannelFund } from './PaymentChannelFund' import { SetFeeTransaction as SetFee } from './SetFee' +import { SetHookTransaction as SetHook } from './SetHook' import { SetRegularKeyTransaction as SetRegularKey } from './SetRegularKey' import { SignerListSetTransaction as SignerListSet } from './SignerListSet' import { XChainAccountCreateCommitTransaction as XChainAccountCreateCommit } from './XChainAccountCreateCommit' @@ -60,6 +61,7 @@ export const transactionTypes: { [key: string]: TransactionMapping } = { PaymentChannelClaim, PaymentChannelFund, SetFee, + SetHook, SetRegularKey, SignerListSet, XChainAccountCreateCommit, diff --git a/src/containers/shared/components/Transaction/test/DefaultSimple.test.tsx b/src/containers/shared/components/Transaction/test/DefaultSimple.test.tsx index ffda234de..25d91a45f 100644 --- a/src/containers/shared/components/Transaction/test/DefaultSimple.test.tsx +++ b/src/containers/shared/components/Transaction/test/DefaultSimple.test.tsx @@ -2,10 +2,16 @@ import NewEscrowCreate from './mock_data/NewEscrowCreate.json' import SetHook from './mock_data/SetHook.json' import SetHook2 from './mock_data/SetHook2.json' import { DefaultSimple } from '../DefaultSimple' -import { createSimpleWrapperFactory } from './createWrapperFactory' +import { createWrapper as createGeneralWrapper } from './createWrapperFactory' import { expectSimpleRowText } from './expectations' +import summarizeTransaction from '../../../../../rippled/lib/txSummary' -const createWrapper = createSimpleWrapperFactory(DefaultSimple) +function createWrapper(tx: any) { + // eslint-disable-next-line no-param-reassign -- needed so parsers aren't triggered + tx.tx.TransactionType = 'DummyTx' + const data = summarizeTransaction(tx, true) + return createGeneralWrapper() +} describe('DefaultSimple', () => { it('renders Simple for basic transaction', () => { diff --git a/src/containers/shared/transactionUtils.ts b/src/containers/shared/transactionUtils.ts index aee77fa15..3d85d8996 100644 --- a/src/containers/shared/transactionUtils.ts +++ b/src/containers/shared/transactionUtils.ts @@ -89,6 +89,12 @@ export const ACCOUNT_FLAGS: Record = { 1: 'asfRequireDest', } +export const HOOK_FLAGS: Record = { + 0x00000001: 'hsfOverride', + 0x00000010: 'hsfNSDelete', + 0x00000100: 'hsfCollect', +} + export const CURRENCY_ORDER = [ 'CNY', 'JPY', @@ -169,7 +175,7 @@ export function buildMemos(trans: Transaction) { return memoList } -export function buildFlags(trans: Transaction) { +export function buildFlags(trans: Transaction): string[] { const flags = TX_FLAGS[trans.tx.TransactionType] || {} const bits = zeroPad((trans.tx.Flags || 0).toString(2), 32).split('') @@ -182,7 +188,20 @@ export function buildFlags(trans: Transaction) { ? TX_FLAGS.all[int] || flags[int] || hex32(int) : undefined }) - .filter((d) => Boolean(d)) + .filter((d) => Boolean(d)) as string[] +} + +export function buildHookFlags(flags: number): string[] { + const bits = zeroPad((flags || 0).toString(2), 32).split('') + + return bits + .map((value, i) => { + const bin = zeroPad(1, 32 - i, true) + const int = parseInt(bin, 2) + // const type = i < 8 ? 'universal' : (i < 16 ? 'type_specific' : 'reserved'); + return value === '1' ? HOOK_FLAGS[int] || hex32(int) : undefined + }) + .filter((d) => Boolean(d)) as string[] } function hex32(d: number): string { @@ -191,7 +210,11 @@ function hex32(d: number): string { return `0x${`00000000${hex}`.slice(-8)}` } -function zeroPad(num: string | number, size: number, back = false): string { +export function zeroPad( + num: string | number, + size: number, + back = false, +): string { let s = String(num) while (s.length < (size || 2)) { s = back ? `${s}0` : `0${s}`