mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Support Cron Amendment (#32)
This commit is contained in:
@@ -29,6 +29,7 @@
|
|||||||
"LEDGER_ENTRY_TYPES": {
|
"LEDGER_ENTRY_TYPES": {
|
||||||
"Invalid": -1,
|
"Invalid": -1,
|
||||||
"AccountRoot": 97,
|
"AccountRoot": 97,
|
||||||
|
"Cron": 65,
|
||||||
"DirectoryNode": 100,
|
"DirectoryNode": 100,
|
||||||
"RippleState": 114,
|
"RippleState": 114,
|
||||||
"Ticket": 84,
|
"Ticket": 84,
|
||||||
@@ -798,6 +799,26 @@
|
|||||||
"type": "UInt32"
|
"type": "UInt32"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"RepeatCount",
|
||||||
|
{
|
||||||
|
"nth": 94,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"DelaySeconds",
|
||||||
|
{
|
||||||
|
"nth": 95,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "UInt32"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"XahauActivationLgrSeq",
|
"XahauActivationLgrSeq",
|
||||||
{
|
{
|
||||||
@@ -1488,6 +1509,16 @@
|
|||||||
"type": "Hash256"
|
"type": "Hash256"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"Cron",
|
||||||
|
{
|
||||||
|
"nth": 95,
|
||||||
|
"isVLEncoded": false,
|
||||||
|
"isSerialized": true,
|
||||||
|
"isSigningField": true,
|
||||||
|
"type": "Hash256"
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"Amount",
|
"Amount",
|
||||||
{
|
{
|
||||||
@@ -2835,6 +2866,8 @@
|
|||||||
"URITokenBuy": 47,
|
"URITokenBuy": 47,
|
||||||
"URITokenCreateSellOffer": 48,
|
"URITokenCreateSellOffer": 48,
|
||||||
"URITokenCancelSellOffer": 49,
|
"URITokenCancelSellOffer": 49,
|
||||||
|
"Cron": 92,
|
||||||
|
"CronSet": 93,
|
||||||
"SetRemarks": 94,
|
"SetRemarks": 94,
|
||||||
"Remit": 95,
|
"Remit": 95,
|
||||||
"GenesisMint": 96,
|
"GenesisMint": 96,
|
||||||
|
|||||||
@@ -74,7 +74,13 @@ class XrplDefinitionsBase {
|
|||||||
.filter(([_key, value]) => value >= 0)
|
.filter(([_key, value]) => value >= 0)
|
||||||
.map(([key, _value]) => key)
|
.map(([key, _value]) => key)
|
||||||
|
|
||||||
const ignoreList = ['EnableAmendment', 'SetFee', 'UNLModify', 'EmitFailure']
|
const ignoreList = [
|
||||||
|
'EnableAmendment',
|
||||||
|
'SetFee',
|
||||||
|
'UNLModify',
|
||||||
|
'EmitFailure',
|
||||||
|
'Cron',
|
||||||
|
]
|
||||||
this.transactionMap = Object.assign(
|
this.transactionMap = Object.assign(
|
||||||
{},
|
{},
|
||||||
...Object.entries(enums.TRANSACTION_TYPES)
|
...Object.entries(enums.TRANSACTION_TYPES)
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
|||||||
|
|
||||||
## Unreleased Changes
|
## Unreleased Changes
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Support for Cron Amendment
|
||||||
|
|
||||||
|
## 4.0.1 (2025-10-03)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* parseTransactionFlags as a utility function in the xrpl package to streamline transactions flags-to-map conversion
|
* parseTransactionFlags as a utility function in the xrpl package to streamline transactions flags-to-map conversion
|
||||||
* Support for XLS-77d Deep-Freeze amendment
|
* Support for XLS-77d Deep-Freeze amendment
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ export default interface AccountRoot extends BaseLedgerEntry, HasPreviousTxnID {
|
|||||||
GovernanceMarks?: string
|
GovernanceMarks?: string
|
||||||
AccountIndex?: number
|
AccountIndex?: number
|
||||||
TouchCount?: number
|
TouchCount?: number
|
||||||
|
/* The cron job that is associated with this account. */
|
||||||
|
Cron?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
17
packages/xahau/src/models/transactions/cron.ts
Normal file
17
packages/xahau/src/models/transactions/cron.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { BaseTransaction } from './common'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cron job to be executed.
|
||||||
|
*
|
||||||
|
* @category Pseudo Transaction Models
|
||||||
|
*/
|
||||||
|
export interface Cron extends BaseTransaction {
|
||||||
|
TransactionType: 'Cron'
|
||||||
|
/**
|
||||||
|
* The ledger index where this pseudo-transaction appears.
|
||||||
|
* This distinguishes the pseudo-transaction from other occurrences of the same change.
|
||||||
|
*/
|
||||||
|
LedgerSequence: number
|
||||||
|
/** The owner of the cron job. */
|
||||||
|
Owner: string
|
||||||
|
}
|
||||||
68
packages/xahau/src/models/transactions/cronSet.ts
Normal file
68
packages/xahau/src/models/transactions/cronSet.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { ValidationError } from '../../errors'
|
||||||
|
|
||||||
|
import { BaseTransaction, validateBaseTransaction } from './common'
|
||||||
|
/**
|
||||||
|
* Transaction Flags for an CronSet Transaction.
|
||||||
|
*
|
||||||
|
* @category Transaction Flags
|
||||||
|
*/
|
||||||
|
export enum CronSetFlags {
|
||||||
|
/**
|
||||||
|
* If set, indicates that the user would like to unset the cron job.
|
||||||
|
*/
|
||||||
|
tfCronUnset = 0x00000001,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CronSet is a transaction model that allows an account to set a cron job.
|
||||||
|
*
|
||||||
|
* @category Transaction Models
|
||||||
|
*/
|
||||||
|
export interface CronSet extends BaseTransaction {
|
||||||
|
TransactionType: 'CronSet'
|
||||||
|
Flags?: number | CronSetFlags
|
||||||
|
RepeatCount?: number
|
||||||
|
DelaySeconds?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_REPEAT_COUNT = 256
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- seconds in a year
|
||||||
|
const MIN_DELAY_SECONDS = 365 * 24 * 60 * 60
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the form and type of an CronSet at runtime.
|
||||||
|
*
|
||||||
|
* @param tx - An CronSet Transaction.
|
||||||
|
* @throws When the CronSet is Malformed.
|
||||||
|
*/
|
||||||
|
export function validateCronSet(tx: Record<string, unknown>): void {
|
||||||
|
validateBaseTransaction(tx)
|
||||||
|
|
||||||
|
if (tx.Flags === CronSetFlags.tfCronUnset) {
|
||||||
|
if (tx.RepeatCount !== undefined || tx.DelaySeconds !== undefined) {
|
||||||
|
throw new ValidationError(
|
||||||
|
'CronSet: RepeatCount and DelaySeconds must not be set when Flags is set to tfCronUnset',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.RepeatCount !== undefined && typeof tx.RepeatCount !== 'number') {
|
||||||
|
throw new ValidationError('CronSet: RepeatCount must be a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.RepeatCount !== undefined && tx.RepeatCount > MAX_REPEAT_COUNT) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`CronSet: RepeatCount must be less than ${MAX_REPEAT_COUNT}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.DelaySeconds !== undefined && typeof tx.DelaySeconds !== 'number') {
|
||||||
|
throw new ValidationError('CronSet: DelaySeconds must be a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx.DelaySeconds !== undefined && tx.DelaySeconds > MIN_DELAY_SECONDS) {
|
||||||
|
throw new ValidationError(
|
||||||
|
`CronSet: DelaySeconds must be less than ${MIN_DELAY_SECONDS}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ export { CheckCancel } from './checkCancel'
|
|||||||
export { CheckCash } from './checkCash'
|
export { CheckCash } from './checkCash'
|
||||||
export { CheckCreate } from './checkCreate'
|
export { CheckCreate } from './checkCreate'
|
||||||
export { ClaimReward, ClaimRewardFlags } from './claimReward'
|
export { ClaimReward, ClaimRewardFlags } from './claimReward'
|
||||||
|
export { Cron } from './cron'
|
||||||
|
export { CronSet, CronSetFlags } from './cronSet'
|
||||||
export { DepositPreauth } from './depositPreauth'
|
export { DepositPreauth } from './depositPreauth'
|
||||||
export { EscrowCancel } from './escrowCancel'
|
export { EscrowCancel } from './escrowCancel'
|
||||||
export { EscrowCreate } from './escrowCreate'
|
export { EscrowCreate } from './escrowCreate'
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { CheckCreate, validateCheckCreate } from './checkCreate'
|
|||||||
import { ClaimReward, validateClaimReward } from './claimReward'
|
import { ClaimReward, validateClaimReward } from './claimReward'
|
||||||
import { Clawback, validateClawback } from './clawback'
|
import { Clawback, validateClawback } from './clawback'
|
||||||
import { BaseTransaction, isIssuedCurrency } from './common'
|
import { BaseTransaction, isIssuedCurrency } from './common'
|
||||||
|
import { Cron } from './cron'
|
||||||
|
import { CronSet, validateCronSet } from './cronSet'
|
||||||
import { DepositPreauth, validateDepositPreauth } from './depositPreauth'
|
import { DepositPreauth, validateDepositPreauth } from './depositPreauth'
|
||||||
import { EnableAmendment } from './enableAmendment'
|
import { EnableAmendment } from './enableAmendment'
|
||||||
import { EscrowCancel, validateEscrowCancel } from './escrowCancel'
|
import { EscrowCancel, validateEscrowCancel } from './escrowCancel'
|
||||||
@@ -68,6 +70,7 @@ export type SubmittableTransaction =
|
|||||||
| CheckCreate
|
| CheckCreate
|
||||||
| ClaimReward
|
| ClaimReward
|
||||||
| Clawback
|
| Clawback
|
||||||
|
| CronSet
|
||||||
| DepositPreauth
|
| DepositPreauth
|
||||||
| EscrowCancel
|
| EscrowCancel
|
||||||
| EscrowCreate
|
| EscrowCreate
|
||||||
@@ -98,7 +101,7 @@ export type SubmittableTransaction =
|
|||||||
*
|
*
|
||||||
* @category Transaction Models
|
* @category Transaction Models
|
||||||
*/
|
*/
|
||||||
export type PseudoTransaction = EnableAmendment | SetFee | UNLModify
|
export type PseudoTransaction = Cron | EnableAmendment | SetFee | UNLModify
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All transactions that can live on the XAHL
|
* All transactions that can live on the XAHL
|
||||||
@@ -210,6 +213,10 @@ export function validate(transaction: Record<string, unknown>): void {
|
|||||||
validateClawback(tx)
|
validateClawback(tx)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'CronSet':
|
||||||
|
validateCronSet(tx)
|
||||||
|
break
|
||||||
|
|
||||||
case 'DepositPreauth':
|
case 'DepositPreauth':
|
||||||
validateDepositPreauth(tx)
|
validateDepositPreauth(tx)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from '../ledger/AccountRoot'
|
} from '../ledger/AccountRoot'
|
||||||
import { AccountSetTfFlags } from '../transactions/accountSet'
|
import { AccountSetTfFlags } from '../transactions/accountSet'
|
||||||
import { GlobalFlags } from '../transactions/common'
|
import { GlobalFlags } from '../transactions/common'
|
||||||
|
import { CronSetFlags } from '../transactions/cronSet'
|
||||||
import { OfferCreateFlags } from '../transactions/offerCreate'
|
import { OfferCreateFlags } from '../transactions/offerCreate'
|
||||||
import { PaymentFlags } from '../transactions/payment'
|
import { PaymentFlags } from '../transactions/payment'
|
||||||
import { PaymentChannelClaimFlags } from '../transactions/paymentChannelClaim'
|
import { PaymentChannelClaimFlags } from '../transactions/paymentChannelClaim'
|
||||||
@@ -52,6 +53,7 @@ const txToFlag = {
|
|||||||
PaymentChannelClaim: PaymentChannelClaimFlags,
|
PaymentChannelClaim: PaymentChannelClaimFlags,
|
||||||
Payment: PaymentFlags,
|
Payment: PaymentFlags,
|
||||||
TrustSet: TrustSetFlags,
|
TrustSet: TrustSetFlags,
|
||||||
|
CronSet: CronSetFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
108
packages/xahau/test/models/cronSet.test.ts
Normal file
108
packages/xahau/test/models/cronSet.test.ts
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { validate, ValidationError } from '../../src'
|
||||||
|
import {
|
||||||
|
CronSetFlags,
|
||||||
|
validateCronSet,
|
||||||
|
} from '../../src/models/transactions/cronSet'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CronSet Transaction Verification Testing.
|
||||||
|
*
|
||||||
|
* Providing runtime verification testing for each specific transaction type.
|
||||||
|
*/
|
||||||
|
describe('CronSet', function () {
|
||||||
|
it(`verifies valid CronSet`, function () {
|
||||||
|
let validCronSet = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Fee: '100',
|
||||||
|
RepeatCount: 256,
|
||||||
|
DelaySeconds: 365 * 24 * 60 * 60,
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => validateCronSet(validCronSet))
|
||||||
|
assert.doesNotThrow(() => validate(validCronSet))
|
||||||
|
|
||||||
|
validCronSet = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Fee: '100',
|
||||||
|
Flags: CronSetFlags.tfCronUnset,
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => validateCronSet(validCronSet))
|
||||||
|
assert.doesNotThrow(() => validate(validCronSet))
|
||||||
|
|
||||||
|
validCronSet = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Fee: '100',
|
||||||
|
Flags: { tfCronUnset: true },
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.doesNotThrow(() => validateCronSet(validCronSet))
|
||||||
|
assert.doesNotThrow(() => validate(validCronSet))
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid Delete Operation`, function () {
|
||||||
|
const invalidDeleteOperation = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Flags: CronSetFlags.tfCronUnset,
|
||||||
|
RepeatCount: 1,
|
||||||
|
DelaySeconds: 1,
|
||||||
|
Fee: '100',
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validateCronSet(invalidDeleteOperation),
|
||||||
|
ValidationError,
|
||||||
|
'CronSet: RepeatCount and DelaySeconds must not be set when Flags is set to tfCronUnset',
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalidDeleteOperation),
|
||||||
|
ValidationError,
|
||||||
|
'CronSet: RepeatCount and DelaySeconds must not be set when Flags is set to tfCronUnset',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`throws w/ invalid RepeatCount`, function () {
|
||||||
|
const invalidRepeatCount = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
RepeatCount: 257,
|
||||||
|
Fee: '100',
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validateCronSet(invalidRepeatCount),
|
||||||
|
ValidationError,
|
||||||
|
'CronSet: RepeatCount must be less than 256',
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalidRepeatCount),
|
||||||
|
ValidationError,
|
||||||
|
'CronSet: RepeatCount must be less than 256',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it(`throws w/ invalid DelaySeconds`, function () {
|
||||||
|
const invalidDelaySeconds = {
|
||||||
|
TransactionType: 'CronSet',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
DelaySeconds: 365 * 24 * 60 * 60 + 1,
|
||||||
|
Fee: '100',
|
||||||
|
} as any
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => validateCronSet(invalidDelaySeconds),
|
||||||
|
ValidationError,
|
||||||
|
`CronSet: DelaySeconds must be less than ${365 * 24 * 60 * 60}`,
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => validate(invalidDelaySeconds),
|
||||||
|
ValidationError,
|
||||||
|
`CronSet: DelaySeconds must be less than ${365 * 24 * 60 * 60}`,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user