From 83a25c6c34bcebc69772861e222d31665a0585df Mon Sep 17 00:00:00 2001 From: tequ Date: Tue, 8 Jul 2025 01:31:55 +0900 Subject: [PATCH] HookCanEmit (#22) --- .../src/enums/definitions.json | 10 +++++++ packages/xahau/src/models/common/xahau.ts | 4 +++ .../xahau/src/models/transactions/setHook.ts | 7 ++++- packages/xahau/src/utils/hooks.ts | 10 +++++++ packages/xahau/src/utils/index.ts | 8 ++++- packages/xahau/test/models/setHook.test.ts | 30 ++++++++++++++++++- 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/packages/xahau-binary-codec/src/enums/definitions.json b/packages/xahau-binary-codec/src/enums/definitions.json index c8e98c42..2c88bfad 100644 --- a/packages/xahau-binary-codec/src/enums/definitions.json +++ b/packages/xahau-binary-codec/src/enums/definitions.json @@ -1478,6 +1478,16 @@ "type": "Hash256" } ], + [ + "HookCanEmit", + { + "nth": 96, + "isVLEncoded": false, + "isSerialized": true, + "isSigningField": true, + "type": "Hash256" + } + ], [ "Amount", { diff --git a/packages/xahau/src/models/common/xahau.ts b/packages/xahau/src/models/common/xahau.ts index 0de6e708..ebcdf676 100644 --- a/packages/xahau/src/models/common/xahau.ts +++ b/packages/xahau/src/models/common/xahau.ts @@ -63,6 +63,10 @@ export interface Hook { * The transactions that triggers the hook. Represented as a 256Hash */ HookOn?: string + /** + * The transactions that can emit from the hook. Represented as a 256Hash + */ + HookCanEmit?: string /** * The namespace of the hook. */ diff --git a/packages/xahau/src/models/transactions/setHook.ts b/packages/xahau/src/models/transactions/setHook.ts index d6a48bff..57eb3811 100644 --- a/packages/xahau/src/models/transactions/setHook.ts +++ b/packages/xahau/src/models/transactions/setHook.ts @@ -66,12 +66,17 @@ export function validateSetHook(tx: Record): void { for (const hook of tx.Hooks) { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Should be a Hook const hookObject = hook as Hook - const { HookOn, HookNamespace } = hookObject.Hook + const { HookOn, HookCanEmit, HookNamespace } = hookObject.Hook if (HookOn !== undefined && !HEX_REGEX.test(HookOn)) { throw new ValidationError( `SetHook: HookOn in Hook must be a 256-bit (32-byte) hexadecimal value`, ) } + if (HookCanEmit !== undefined && !HEX_REGEX.test(HookCanEmit)) { + throw new ValidationError( + `SetHook: HookCanEmit in Hook must be a 256-bit (32-byte) hexadecimal value`, + ) + } if (HookNamespace !== undefined && !HEX_REGEX.test(HookNamespace)) { throw new ValidationError( `SetHook: HookNamespace in Hook must be a 256-bit (32-byte) hexadecimal value`, diff --git a/packages/xahau/src/utils/hooks.ts b/packages/xahau/src/utils/hooks.ts index efefc111..7a432dd8 100644 --- a/packages/xahau/src/utils/hooks.ts +++ b/packages/xahau/src/utils/hooks.ts @@ -55,6 +55,16 @@ export function calculateHookOn(arr: Array): string { return hash.toUpperCase() } +/** + * Calculate the hook can emit + * + * @param arr - array of transaction types + * @returns the hook can emit + */ +export function calculateHookCanEmit(arr: Array): string { + return calculateHookOn(arr) +} + function isHex(value: string): boolean { return /^[0-9A-F]+$/iu.test(value) } diff --git a/packages/xahau/src/utils/index.ts b/packages/xahau/src/utils/index.ts index 64b4c22f..777969bf 100644 --- a/packages/xahau/src/utils/index.ts +++ b/packages/xahau/src/utils/index.ts @@ -46,7 +46,12 @@ import { hashPaymentChannel, hashURIToken, } from './hashes' -import { calculateHookOn, hexHookParameters, TTS } from './hooks' +import { + calculateHookOn, + calculateHookCanEmit, + hexHookParameters, + TTS, +} from './hooks' import { percentToTransferRate, decimalToTransferRate, @@ -227,6 +232,7 @@ export { encodeForSigning, encodeForSigningClaim, calculateHookOn, + calculateHookCanEmit, hexHookParameters, TTS, } diff --git a/packages/xahau/test/models/setHook.test.ts b/packages/xahau/test/models/setHook.test.ts index 3ebb8d82..ff7b23b1 100644 --- a/packages/xahau/test/models/setHook.test.ts +++ b/packages/xahau/test/models/setHook.test.ts @@ -9,7 +9,7 @@ import { validateSetHook } from '../../src/models/transactions/setHook' * Providing runtime verification testing for each specific transaction type. */ describe('SetHook', function () { - let setHookTx + let setHookTx: any beforeEach(function () { setHookTx = { @@ -24,6 +24,8 @@ describe('SetHook', function () { '0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22', HookOn: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7', + HookCanEmit: + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7', Flags: 1, HookApiVersion: 0, HookNamespace: @@ -114,6 +116,32 @@ describe('SetHook', function () { assert.throws(() => validate(setHookTx), ValidationError, errorMessage) }) + it(`throws w/ invalid HookCanEmit in Hooks`, function () { + setHookTx.Hooks = [ + { + Hook: { + CreateCode: + '0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22', + HookOn: + 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFF7', + HookCanEmit: '', + Flags: 1, + HookApiVersion: 0, + HookNamespace: + '4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9', + }, + }, + ] + const errorMessage = + 'SetHook: HookCanEmit in Hook must be a 256-bit (32-byte) hexadecimal value' + assert.throws( + () => validateSetHook(setHookTx), + ValidationError, + errorMessage, + ) + assert.throws(() => validate(setHookTx), ValidationError, errorMessage) + }) + it(`throws w/ invalid HookNamespace in Hooks`, function () { setHookTx.SignerQuorum = 2 setHookTx.Hooks = [