mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 20:25:48 +00:00
update hook
update hook add test and validation add estimate fee func fix estimated fee error add hook utils
This commit is contained in:
@@ -7,6 +7,8 @@ export * from './models'
|
|||||||
|
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
|
|
||||||
|
export * from './sugar'
|
||||||
|
|
||||||
export * from './errors'
|
export * from './errors'
|
||||||
|
|
||||||
export { default as Wallet } from './Wallet'
|
export { default as Wallet } from './Wallet'
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ export interface HookGrant {
|
|||||||
*/
|
*/
|
||||||
HookGrant: {
|
HookGrant: {
|
||||||
/**
|
/**
|
||||||
*
|
* The hook hash of the grant.
|
||||||
*/
|
*/
|
||||||
HookHash: string
|
HookHash: string
|
||||||
/**
|
/**
|
||||||
*
|
* The account authorized on the grant.
|
||||||
*/
|
*/
|
||||||
Authorize?: string
|
Authorize?: string
|
||||||
}
|
}
|
||||||
@@ -79,13 +79,13 @@ export interface HookParameter {
|
|||||||
*/
|
*/
|
||||||
HookParameter: {
|
HookParameter: {
|
||||||
/**
|
/**
|
||||||
*
|
* The name of the parameter.
|
||||||
*/
|
*/
|
||||||
HookParameterName: string
|
HookParameterName: string
|
||||||
/**
|
/**
|
||||||
*
|
* The value of the parameter.
|
||||||
*/
|
*/
|
||||||
HookParameterValue: number
|
HookParameterValue: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,31 +98,31 @@ export interface Hook {
|
|||||||
*/
|
*/
|
||||||
Hook: {
|
Hook: {
|
||||||
/**
|
/**
|
||||||
*
|
* The code that is executed when the hook is triggered.
|
||||||
*/
|
*/
|
||||||
CreateCode: string
|
CreateCode: string
|
||||||
/**
|
/**
|
||||||
*
|
* The flags that are set on the hook.
|
||||||
*/
|
*/
|
||||||
Flags: number
|
Flags: number
|
||||||
/**
|
/**
|
||||||
*
|
* The transactions that triggers the hook. Represented as a 256Hash
|
||||||
*/
|
*/
|
||||||
HookOn?: string
|
HookOn?: string
|
||||||
/**
|
/**
|
||||||
*
|
* The namespace of the hook.
|
||||||
*/
|
*/
|
||||||
HookNamespace?: string
|
HookNamespace?: string
|
||||||
/**
|
/**
|
||||||
*
|
* The API version of the hook.
|
||||||
*/
|
*/
|
||||||
HookApiVersion?: number
|
HookApiVersion?: number
|
||||||
/**
|
/**
|
||||||
*
|
* The parameters of the hook.
|
||||||
*/
|
*/
|
||||||
HookParameters?: HookParameter[]
|
HookParameters?: HookParameter[]
|
||||||
/**
|
/**
|
||||||
*
|
* The grants of the hook.
|
||||||
*/
|
*/
|
||||||
HookGrants?: HookGrant[]
|
HookGrants?: HookGrant[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export interface SetHook extends BaseTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MAX_HOOKS = 4
|
const MAX_HOOKS = 4
|
||||||
|
const HEX_REGEX = /^[0-9A-Fa-f]{64}$/u
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify the form and type of an SetHook at runtime.
|
* Verify the form and type of an SetHook at runtime.
|
||||||
@@ -27,21 +28,29 @@ const MAX_HOOKS = 4
|
|||||||
export function validateSetHook(tx: Record<string, unknown>): void {
|
export function validateSetHook(tx: Record<string, unknown>): void {
|
||||||
validateBaseTransaction(tx)
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
if (tx.Hooks === undefined) {
|
|
||||||
throw new ValidationError('SetHook: missing field Hooks')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Array.isArray(tx.Hooks)) {
|
if (!Array.isArray(tx.Hooks)) {
|
||||||
throw new ValidationError('SetHook: invalid Hooks')
|
throw new ValidationError('SetHook: invalid Hooks')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.Hooks.length === 0) {
|
|
||||||
throw new ValidationError('SetHook: need at least 1 hook in Hooks')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx.Hooks.length > MAX_HOOKS) {
|
if (tx.Hooks.length > MAX_HOOKS) {
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
`SetHook: maximum of ${MAX_HOOKS} hooks allowed in Hooks`,
|
`SetHook: maximum of ${MAX_HOOKS} hooks allowed in Hooks`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (HookOn !== undefined && !HEX_REGEX.test(HookOn)) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`SetHook: HookOn 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`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Transaction } from '../models/transactions'
|
|||||||
import { setTransactionFlagsToNumber } from '../models/utils/flags'
|
import { setTransactionFlagsToNumber } from '../models/utils/flags'
|
||||||
import { xrpToDrops } from '../utils'
|
import { xrpToDrops } from '../utils'
|
||||||
|
|
||||||
import getFeeXrp from './getFeeXrp'
|
import { getFeeXrp } from './getFeeXrp'
|
||||||
|
|
||||||
// Expire unconfirmed transactions after 20 ledger versions, approximately 1 minute, by default
|
// Expire unconfirmed transactions after 20 ledger versions, approximately 1 minute, by default
|
||||||
const LEDGER_OFFSET = 20
|
const LEDGER_OFFSET = 20
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const BASE_10 = 10
|
|||||||
* @param cushion - The fee cushion to use.
|
* @param cushion - The fee cushion to use.
|
||||||
* @returns The transaction fee.
|
* @returns The transaction fee.
|
||||||
*/
|
*/
|
||||||
export default async function getFeeXrp(
|
export async function getFeeXrp(
|
||||||
client: Client,
|
client: Client,
|
||||||
cushion?: number,
|
cushion?: number,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
@@ -43,3 +43,22 @@ export default async function getFeeXrp(
|
|||||||
// Round fee to 6 decimal places
|
// Round fee to 6 decimal places
|
||||||
return new BigNumber(fee.toFixed(NUM_DECIMAL_PLACES)).toString(BASE_10)
|
return new BigNumber(fee.toFixed(NUM_DECIMAL_PLACES)).toString(BASE_10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the estimated transaction fee.
|
||||||
|
* Note: This is a public API that can be called directly.
|
||||||
|
*
|
||||||
|
* @param client - The Client used to connect to the ledger.
|
||||||
|
* @param txBlob - The encoded transaction to estimate the fee for.
|
||||||
|
* @returns The transaction fee.
|
||||||
|
*/
|
||||||
|
export async function getFeeEstimateXrp(
|
||||||
|
client: Client,
|
||||||
|
txBlob: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const response = await client.request({
|
||||||
|
command: 'fee',
|
||||||
|
tx_blob: txBlob,
|
||||||
|
})
|
||||||
|
return response.result.drops.base_fee
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export { getBalances, getXrpBalance } from './balances'
|
|||||||
export { default as getLedgerIndex } from './getLedgerIndex'
|
export { default as getLedgerIndex } from './getLedgerIndex'
|
||||||
|
|
||||||
export { default as getOrderbook } from './getOrderbook'
|
export { default as getOrderbook } from './getOrderbook'
|
||||||
|
export { getFeeXrp, getFeeEstimateXrp } from './getFeeXrp'
|
||||||
|
|
||||||
export * from './submit'
|
export * from './submit'
|
||||||
|
|
||||||
|
|||||||
128
packages/xrpl/src/utils/hooks.ts
Normal file
128
packages/xrpl/src/utils/hooks.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* @module tts
|
||||||
|
* @description
|
||||||
|
* This module contains the transaction types and the function to calculate the hook on
|
||||||
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- Required
|
||||||
|
import createHash = require('create-hash')
|
||||||
|
|
||||||
|
import { HookParameter } from '../models/common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constant tts
|
||||||
|
* @description
|
||||||
|
* Transaction types
|
||||||
|
*/
|
||||||
|
export const tts = {
|
||||||
|
ttPAYMENT: 0,
|
||||||
|
ttESCROW_CREATE: 1,
|
||||||
|
ttESCROW_FINISH: 2,
|
||||||
|
ttACCOUNT_SET: 3,
|
||||||
|
ttESCROW_CANCEL: 4,
|
||||||
|
ttREGULAR_KEY_SET: 5,
|
||||||
|
ttOFFER_CREATE: 7,
|
||||||
|
ttOFFER_CANCEL: 8,
|
||||||
|
ttTICKET_CREATE: 10,
|
||||||
|
ttSIGNER_LIST_SET: 12,
|
||||||
|
ttPAYCHAN_CREATE: 13,
|
||||||
|
ttPAYCHAN_FUND: 14,
|
||||||
|
ttPAYCHAN_CLAIM: 15,
|
||||||
|
ttCHECK_CREATE: 16,
|
||||||
|
ttCHECK_CASH: 17,
|
||||||
|
ttCHECK_CANCEL: 18,
|
||||||
|
ttDEPOSIT_PREAUTH: 19,
|
||||||
|
ttTRUST_SET: 20,
|
||||||
|
ttACCOUNT_DELETE: 21,
|
||||||
|
ttHOOK_SET: 22,
|
||||||
|
ttNFTOKEN_MINT: 25,
|
||||||
|
ttNFTOKEN_BURN: 26,
|
||||||
|
ttNFTOKEN_CREATE_OFFER: 27,
|
||||||
|
ttNFTOKEN_CANCEL_OFFER: 28,
|
||||||
|
ttNFTOKEN_ACCEPT_OFFER: 29,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef TTS
|
||||||
|
* @description
|
||||||
|
* Transaction types
|
||||||
|
*/
|
||||||
|
export type TTS = typeof tts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the hook on
|
||||||
|
*
|
||||||
|
* @param arr - array of transaction types
|
||||||
|
* @returns the hook on
|
||||||
|
*/
|
||||||
|
export function calculateHookOn(arr: Array<keyof TTS>): string {
|
||||||
|
let hash = '0x3e3ff5bf'
|
||||||
|
arr.forEach((nth) => {
|
||||||
|
let value = BigInt(hash)
|
||||||
|
// eslint-disable-next-line no-bitwise -- Required
|
||||||
|
value ^= BigInt(1) << BigInt(tts[nth])
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- Required
|
||||||
|
hash = `0x${value.toString(16)}`
|
||||||
|
})
|
||||||
|
hash = hash.replace('0x', '')
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- Required
|
||||||
|
hash = hash.padStart(64, '0')
|
||||||
|
return hash.toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the sha256 of a string
|
||||||
|
*
|
||||||
|
* @param string - the string to calculate the sha256
|
||||||
|
* @returns the sha256
|
||||||
|
*/
|
||||||
|
export async function sha256(string: string): Promise<string> {
|
||||||
|
const hash = createHash('sha256')
|
||||||
|
hash.update(string)
|
||||||
|
const hashBuffer = hash.digest()
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||||
|
const hashHex = hashArray
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- Required
|
||||||
|
.map((bytes) => bytes.toString(16).padStart(2, '0'))
|
||||||
|
.join('')
|
||||||
|
return hashHex
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the hex of a namespace
|
||||||
|
*
|
||||||
|
* @param namespace - the namespace to calculate the hex
|
||||||
|
* @returns the hex
|
||||||
|
*/
|
||||||
|
export async function hexNamespace(namespace: string): Promise<string> {
|
||||||
|
return (await sha256(namespace)).toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the hex of the hook parameters
|
||||||
|
*
|
||||||
|
* @param data - the hook parameters
|
||||||
|
* @returns the hex of the hook parameters
|
||||||
|
*/
|
||||||
|
export function hexHookParameters(data: HookParameter[]): HookParameter[] {
|
||||||
|
const hookParameters: HookParameter[] = []
|
||||||
|
for (const parameter of data) {
|
||||||
|
hookParameters.push({
|
||||||
|
HookParameter: {
|
||||||
|
HookParameterName: Buffer.from(
|
||||||
|
parameter.HookParameter.HookParameterName,
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
|
.toString('hex')
|
||||||
|
.toUpperCase(),
|
||||||
|
HookParameterValue: Buffer.from(
|
||||||
|
parameter.HookParameter.HookParameterValue,
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
|
.toString('hex')
|
||||||
|
.toUpperCase(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return hookParameters
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
hashEscrow,
|
hashEscrow,
|
||||||
hashPaymentChannel,
|
hashPaymentChannel,
|
||||||
} from './hashes'
|
} from './hashes'
|
||||||
|
import { calculateHookOn, hexNamespace, hexHookParameters, TTS } from './hooks'
|
||||||
import parseNFTokenID from './parseNFTokenID'
|
import parseNFTokenID from './parseNFTokenID'
|
||||||
import {
|
import {
|
||||||
percentToTransferRate,
|
percentToTransferRate,
|
||||||
@@ -222,4 +223,8 @@ export {
|
|||||||
getNFTokenID,
|
getNFTokenID,
|
||||||
createCrossChainPayment,
|
createCrossChainPayment,
|
||||||
parseNFTokenID,
|
parseNFTokenID,
|
||||||
|
calculateHookOn,
|
||||||
|
hexNamespace,
|
||||||
|
hexHookParameters,
|
||||||
|
TTS,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
|
|
||||||
import getFeeXrp from '../../src/sugar/getFeeXrp'
|
import { getFeeXrp } from '../../src/sugar/getFeeXrp'
|
||||||
import rippled from '../fixtures/rippled'
|
import rippled from '../fixtures/rippled'
|
||||||
import {
|
import {
|
||||||
setupClient,
|
setupClient,
|
||||||
|
|||||||
150
packages/xrpl/test/models/setHook.test.ts
Normal file
150
packages/xrpl/test/models/setHook.test.ts
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import { validateSetHook } from '../../src/models/transactions/setHook'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SetHook Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('SetHook', function () {
|
||||||
|
let setHookTx
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
setHookTx = {
|
||||||
|
Flags: 0,
|
||||||
|
TransactionType: 'SetHook',
|
||||||
|
Account: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn',
|
||||||
|
Fee: '12',
|
||||||
|
Hooks: [
|
||||||
|
{
|
||||||
|
Hook: {
|
||||||
|
CreateCode:
|
||||||
|
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||||
|
HookOn:
|
||||||
|
'000000000000000000000000000000000000000000000000000000003E3FF5B7',
|
||||||
|
Flags: 1,
|
||||||
|
HookApiVersion: 0,
|
||||||
|
HookNamespace:
|
||||||
|
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`verifies valid SetHook`, function () {
|
||||||
|
assert.doesNotThrow(() => validateSetHook(setHookTx))
|
||||||
|
assert.doesNotThrow(() => validate(setHookTx))
|
||||||
|
})
|
||||||
|
|
||||||
|
// it(`throws w/ empty Hooks`, function () {
|
||||||
|
// setHookTx.Hooks = []
|
||||||
|
|
||||||
|
// assert.throws(
|
||||||
|
// () => validateSetHook(setHookTx),
|
||||||
|
// ValidationError,
|
||||||
|
// 'SetHook: need at least 1 member in Hooks',
|
||||||
|
// )
|
||||||
|
// assert.throws(
|
||||||
|
// () => validate(setHookTx),
|
||||||
|
// ValidationError,
|
||||||
|
// 'SetHook: need at least 1 member in Hooks',
|
||||||
|
// )
|
||||||
|
// })
|
||||||
|
|
||||||
|
it(`throws w/ invalid Hooks`, function () {
|
||||||
|
setHookTx.Hooks = 'khgfgyhujk'
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validateSetHook(setHookTx),
|
||||||
|
ValidationError,
|
||||||
|
'SetHook: invalid Hooks',
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => validate(setHookTx),
|
||||||
|
ValidationError,
|
||||||
|
'SetHook: invalid Hooks',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ maximum of 4 members allowed in Hooks`, function () {
|
||||||
|
setHookTx.Hooks = []
|
||||||
|
const hook = {
|
||||||
|
Hook: {
|
||||||
|
CreateCode:
|
||||||
|
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||||
|
HookOn:
|
||||||
|
'000000000000000000000000000000000000000000000000000000003E3FF5B7',
|
||||||
|
Flags: 1,
|
||||||
|
HookApiVersion: 0,
|
||||||
|
HookNamespace:
|
||||||
|
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
setHookTx.Hooks.push(hook)
|
||||||
|
setHookTx.Hooks.push(hook)
|
||||||
|
setHookTx.Hooks.push(hook)
|
||||||
|
setHookTx.Hooks.push(hook)
|
||||||
|
setHookTx.Hooks.push(hook)
|
||||||
|
|
||||||
|
const errorMessage = 'SetHook: maximum of 4 hooks allowed in Hooks'
|
||||||
|
assert.throws(
|
||||||
|
() => validateSetHook(setHookTx),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid HookOn in Hooks`, function () {
|
||||||
|
setHookTx.SignerQuorum = 2
|
||||||
|
setHookTx.Hooks = [
|
||||||
|
{
|
||||||
|
Hook: {
|
||||||
|
CreateCode:
|
||||||
|
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||||
|
HookOn: '',
|
||||||
|
Flags: 1,
|
||||||
|
HookApiVersion: 0,
|
||||||
|
HookNamespace:
|
||||||
|
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const errorMessage =
|
||||||
|
'SetHook: HookOn 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 = [
|
||||||
|
{
|
||||||
|
Hook: {
|
||||||
|
CreateCode:
|
||||||
|
'0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22',
|
||||||
|
HookOn:
|
||||||
|
'000000000000000000000000000000000000000000000000000000003E3FF5B7',
|
||||||
|
Flags: 1,
|
||||||
|
HookApiVersion: 0,
|
||||||
|
HookNamespace: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const errorMessage =
|
||||||
|
'SetHook: HookNamespace in Hook must be a 256-bit (32-byte) hexadecimal value'
|
||||||
|
assert.throws(
|
||||||
|
() => validateSetHook(setHookTx),
|
||||||
|
ValidationError,
|
||||||
|
errorMessage,
|
||||||
|
)
|
||||||
|
assert.throws(() => validate(setHookTx), ValidationError, errorMessage)
|
||||||
|
})
|
||||||
|
})
|
||||||
58
packages/xrpl/test/utils/hooks.test.ts
Normal file
58
packages/xrpl/test/utils/hooks.test.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import {
|
||||||
|
calculateHookOn,
|
||||||
|
hexNamespace,
|
||||||
|
hexHookParameters,
|
||||||
|
TTS,
|
||||||
|
} from '../../src'
|
||||||
|
|
||||||
|
describe('test hook on', function () {
|
||||||
|
it('all', function () {
|
||||||
|
const result = calculateHookOn([])
|
||||||
|
assert.equal(
|
||||||
|
result,
|
||||||
|
'000000000000000000000000000000000000000000000000000000003E3FF5BF',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it('one', function () {
|
||||||
|
const invokeOn: Array<keyof TTS> = ['ttACCOUNT_SET']
|
||||||
|
const result = calculateHookOn(invokeOn)
|
||||||
|
assert.equal(
|
||||||
|
result,
|
||||||
|
'000000000000000000000000000000000000000000000000000000003E3FF5B7',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('test hook namespace', function () {
|
||||||
|
it('basic', async function () {
|
||||||
|
const result = await hexNamespace('starter')
|
||||||
|
assert.equal(
|
||||||
|
result,
|
||||||
|
'4FF9961269BF7630D32E15276569C94470174A5DA79FA567C0F62251AA9A36B9',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('test hook parameters', function () {
|
||||||
|
it('basic', async function () {
|
||||||
|
const parameters = [
|
||||||
|
{
|
||||||
|
HookParameter: {
|
||||||
|
HookParameterName: 'name1',
|
||||||
|
HookParameterValue: 'value1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const result = hexHookParameters(parameters)
|
||||||
|
assert.deepEqual(result, [
|
||||||
|
{
|
||||||
|
HookParameter: {
|
||||||
|
HookParameterName: '6E616D6531',
|
||||||
|
HookParameterValue: '76616C756531',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user