From 23411acb0444441b60848c75811dff8e2ac906eb Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Sun, 21 Apr 2024 15:38:29 +0100 Subject: [PATCH 01/15] feat: support for custom definitions on xrpl methods: sign, encode, encodeForSigning, decode, computeSignature. --- .vscode/settings.json | 2 +- packages/ripple-binary-codec/README.md | 14 +++++------ packages/xrpl/src/Wallet/index.ts | 20 ++++++++++++--- packages/xrpl/src/utils/index.ts | 34 ++++++++++++++++++++------ 4 files changed, 50 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5dc2e1cf8e..ef2c734c23 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,7 +39,7 @@ "enable": true }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, diff --git a/packages/ripple-binary-codec/README.md b/packages/ripple-binary-codec/README.md index a201f05266..b7f440d4c5 100644 --- a/packages/ripple-binary-codec/README.md +++ b/packages/ripple-binary-codec/README.md @@ -10,7 +10,7 @@ Functions to encode/decode to/from the ripple [binary serialization format](http ``` -### decode(binary: string): object +### decode(binary: string, definitions?: XrplDefinitionsBase): object Decode a hex-string into a transaction object. ```js > api.decode('1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337') @@ -26,7 +26,7 @@ Decode a hex-string into a transaction object. } ``` -### encode(json: object): string +### encode(json: object, definitions?: XrplDefinitionsBase): string Encode a transaction object into a hex-string. Note that encode filters out fields with undefined values. ```js > api.encode({ @@ -37,12 +37,12 @@ Encode a transaction object into a hex-string. Note that encode filters out fiel OwnerCount: 0, PreviousTxnID: 'DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF', Balance: '10000000000', - Account: 'rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv' + Account: 'rLs1MzkFWCxTbuAHgjeTZK4fcCDDnf2KRv' }) '1100612200000000240000000125000000072D0000000055DF530FB14C5304852F20080B0A8EEF3A6BDD044F41F4EBBD68B8B321145FE4FF6240000002540BE4008114D0F5430B66E06498D4CEEC816C7B3337F9982337' ``` -#### X-Address Compatibility +#### X-Address Compatibility * ripple-binary-codec handles X-addresses by looking for a few specific files (Account/SourceTag, Destination/DestinationTag). * If other fields (in the future) must to support X-addresses with tags, this library will need to be updated. * When decoding rippled binary, the output will always output classic address + tag, with no X-addresses. X-address support only applies when encoding to binary. @@ -54,7 +54,7 @@ Encode a transaction object into a hex-string. Note that encode filters out fiel * When _decoding_, if a currency code is three uppercase letters or numbers (`/^[A-Z0-9]{3}$/`), then it will be decoded into that string. For example,`0000000000000000000000004142430000000000` decodes as `ABC`. * When decoding, if a currency code is does not match the regex, then it is not considered to be an ISO 4217 or pseudo-ISO currency. ripple-binary-codec will return a 160-bit hex-string (40 hex characters). For example, `0000000000000000000000006142430000000000` (`aBC`) decodes as `0000000000000000000000006142430000000000` because it contains a lowercase letter. -### encodeForSigning(json: object): string +### encodeForSigning(json: object, definitions?: XrplDefinitionsBase): string Encode the transaction object for signing. @@ -62,7 +62,7 @@ Encode the transaction object for signing. Encode the transaction object for payment channel claim. -### encodeForMultisigning(json: object, signer: string): string +### encodeForMultisigning(json: object, signer: string, definitions?: XrplDefinitionsBase): string Encode the transaction object for multi-signing. @@ -72,7 +72,7 @@ Encode the transaction object for multi-signing. '5D06F4C3362FE1D0' ``` -### decodeQuality(value: string): string +### decodeQuality(value: string): string ```js > api.decodeQuality('5D06F4C3362FE1D0') '195796912.5171664' diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index c5ce5baca5..4fdf2f480a 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -13,6 +13,7 @@ import { encodeForSigning, encodeForMultisigning, encode, + XrplDefinitionsBase, } from 'ripple-binary-codec' import { deriveAddress, @@ -367,15 +368,17 @@ export class Wallet { * @param this - Wallet instance. * @param transaction - A transaction to be signed offline. * @param multisign - Specify true/false to use multisign or actual address (classic/x-address) to make multisign tx request. + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns A signed transaction. * @throws ValidationError if the transaction is already signed or does not encode/decode to same result. * @throws XrplError if the issued currency being signed is XRP ignoring case. */ - // eslint-disable-next-line max-lines-per-function -- introduced more checks to support both string and boolean inputs. + // eslint-disable-next-line max-lines-per-function, max-params -- introduced more checks to support string and boolean inputs. public sign( this: Wallet, transaction: Transaction, multisign?: boolean | string, + definitions?: XrplDefinitionsBase, ): { tx_blob: string hash: string @@ -420,6 +423,7 @@ export class Wallet { txToSignAndEncode, this.privateKey, multisignAddress, + definitions, ), } txToSignAndEncode.Signers = [{ Signer: signer }] @@ -427,10 +431,12 @@ export class Wallet { txToSignAndEncode.TxnSignature = computeSignature( txToSignAndEncode, this.privateKey, + undefined, + definitions, ) } - const serialized = encode(txToSignAndEncode) + const serialized = encode(txToSignAndEncode, definitions) return { tx_blob: serialized, hash: hashSignedTx(serialized), @@ -466,22 +472,28 @@ export class Wallet { * @param tx - A transaction to sign. * @param privateKey - A key to sign the transaction with. * @param signAs - Multisign only. An account address to include in the Signer field. + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * Can be either a classic address or an XAddress. * @returns A signed transaction in the proper format. */ +// eslint-disable-next-line max-params -- Needs 4 params function computeSignature( tx: Transaction, privateKey: string, signAs?: string, + definitions?: XrplDefinitionsBase, ): string { if (signAs) { const classicAddress = isValidXAddress(signAs) ? xAddressToClassicAddress(signAs).classicAddress : signAs - return sign(encodeForMultisigning(tx, classicAddress), privateKey) + return sign( + encodeForMultisigning(tx, classicAddress, definitions), + privateKey, + ) } - return sign(encodeForSigning(tx), privateKey) + return sign(encodeForSigning(tx, definitions), privateKey) } /** diff --git a/packages/xrpl/src/utils/index.ts b/packages/xrpl/src/utils/index.ts index c96afd4151..65aa56fdac 100644 --- a/packages/xrpl/src/utils/index.ts +++ b/packages/xrpl/src/utils/index.ts @@ -20,6 +20,7 @@ import { encodeForMultisigning as rbcEncodeForMultisigning, encodeForSigning as rbcEncodeForSigning, encodeForSigningClaim as rbcEncodeForSigningClaim, + XrplDefinitionsBase, } from 'ripple-binary-codec' import { verify as verifyKeypairSignature } from 'ripple-keypairs' @@ -86,20 +87,28 @@ function isValidSecret(secret: string): boolean { * Encodes a LedgerEntry or Transaction into a hex string * * @param object - LedgerEntry or Transaction in JSON format. + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns A hex string representing the encoded object. */ -function encode(object: Transaction | LedgerEntry): string { - return rbcEncode(object) +function encode( + object: Transaction | LedgerEntry, + definitions?: XrplDefinitionsBase, +): string { + return rbcEncode(object, definitions) } /** * Encodes a Transaction for signing * * @param object - LedgerEntry in JSON or Transaction format. + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns A hex string representing the encoded object. */ -function encodeForSigning(object: Transaction): string { - return rbcEncodeForSigning(object) +function encodeForSigning( + object: Transaction, + definitions?: XrplDefinitionsBase, +): string { + return rbcEncodeForSigning(object, definitions) } /** @@ -117,20 +126,29 @@ function encodeForSigningClaim(object: PaymentChannelClaim): string { * * @param object - Transaction in JSON format. * @param signer - The address of the account signing this transaction + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns A hex string representing the encoded object. */ -function encodeForMultiSigning(object: Transaction, signer: string): string { - return rbcEncodeForMultisigning(object, signer) +function encodeForMultiSigning( + object: Transaction, + signer: string, + definitions?: XrplDefinitionsBase, +): string { + return rbcEncodeForMultisigning(object, signer, definitions) } /** * Decodes a hex string into a transaction | ledger entry * * @param hex - hex string in the XRPL serialization format. + * @param definitions Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns The hex string decoded according to XRPL serialization format. */ -function decode(hex: string): Record { - return rbcDecode(hex) +function decode( + hex: string, + definitions?: XrplDefinitionsBase, +): Record { + return rbcDecode(hex, definitions) } /** From 9249824731c0b7a9aaa5f8b0ca70e2bb410e09a7 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Tue, 23 Apr 2024 13:27:43 +0100 Subject: [PATCH 02/15] chore: tests --- .../ripple-binary-codec/src/types/amount.ts | 1 - packages/xrpl/src/Wallet/index.ts | 8 +- .../src/models/transactions/transaction.ts | 12 +- packages/xrpl/src/utils/hashes/hashLedger.ts | 11 +- packages/xrpl/test/fixtures/requests/index.ts | 2 + .../requests/signAsCustomDefinition.json | 19 + .../xrpl/test/fixtures/responses/index.ts | 4 + .../responses/signAsCustomDefinition.json | 4 + .../responses/signCustomDefinition.json | 4 + .../fixtures/rippled/customDefinition.json | 3002 +++++++++++++++++ packages/xrpl/test/fixtures/rippled/index.ts | 6 + packages/xrpl/test/wallet/index.test.ts | 48 +- 12 files changed, 3109 insertions(+), 12 deletions(-) create mode 100644 packages/xrpl/test/fixtures/requests/signAsCustomDefinition.json create mode 100644 packages/xrpl/test/fixtures/responses/signAsCustomDefinition.json create mode 100644 packages/xrpl/test/fixtures/responses/signCustomDefinition.json create mode 100644 packages/xrpl/test/fixtures/rippled/customDefinition.json diff --git a/packages/ripple-binary-codec/src/types/amount.ts b/packages/ripple-binary-codec/src/types/amount.ts index b92ebf4fc2..405770c5a8 100644 --- a/packages/ripple-binary-codec/src/types/amount.ts +++ b/packages/ripple-binary-codec/src/types/amount.ts @@ -123,7 +123,6 @@ class Amount extends SerializedType { const issuer = AccountID.from(value.issuer).toBytes() return new Amount(concat([amount, currency, issuer])) } - throw new Error('Invalid type to construct an Amount') } diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 4fdf2f480a..0752938268 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -409,7 +409,10 @@ export class Wallet { * This will throw a more clear error for JS users if the supplied transaction has incorrect formatting */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type - validate(tx as unknown as Record) + validate( + tx as unknown as Record, + definitions ? true : false, + ) const txToSignAndEncode = { ...tx } @@ -437,9 +440,10 @@ export class Wallet { } const serialized = encode(txToSignAndEncode, definitions) + return { tx_blob: serialized, - hash: hashSignedTx(serialized), + hash: hashSignedTx(serialized, definitions), } } diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 1207d81a19..506d33efd5 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -169,7 +169,10 @@ export interface TransactionAndMetadata< * @throws ValidationError When the Transaction is malformed. * @category Utilities */ -export function validate(transaction: Record): void { +export function validate( + transaction: Record, + customDefinition?: boolean, +): void { const tx = { ...transaction } if (tx.TransactionType == null) { throw new ValidationError('Object does not have a `TransactionType`') @@ -395,8 +398,9 @@ export function validate(transaction: Record): void { break default: - throw new ValidationError( - `Invalid field TransactionType: ${tx.TransactionType}`, - ) + if (!customDefinition) + throw new ValidationError( + `Invalid field TransactionType: ${tx.TransactionType}`, + ) } } diff --git a/packages/xrpl/src/utils/hashes/hashLedger.ts b/packages/xrpl/src/utils/hashes/hashLedger.ts index 1cf9997226..b6a7ea19a0 100644 --- a/packages/xrpl/src/utils/hashes/hashLedger.ts +++ b/packages/xrpl/src/utils/hashes/hashLedger.ts @@ -5,7 +5,7 @@ import { bytesToHex } from '@xrplf/isomorphic/utils' import BigNumber from 'bignumber.js' -import { decode, encode } from 'ripple-binary-codec' +import { decode, encode, XrplDefinitionsBase } from 'ripple-binary-codec' import { ValidationError, XrplError } from '../../errors' import type { Ledger } from '../../models/ledger' @@ -68,15 +68,18 @@ function addLengthPrefix(hex: string): string { * @throws ValidationError if the Transaction is unsigned.\ * @category Utilities */ -export function hashSignedTx(tx: Transaction | string): string { +export function hashSignedTx( + tx: Transaction | string, + definitions?: XrplDefinitionsBase, +): string { let txBlob: string let txObject: Transaction if (typeof tx === 'string') { txBlob = tx /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Required until updated in binary codec. */ - txObject = decode(tx) as unknown as Transaction + txObject = decode(tx, definitions) as unknown as Transaction } else { - txBlob = encode(tx) + txBlob = encode(tx, definitions) txObject = tx } diff --git a/packages/xrpl/test/fixtures/requests/index.ts b/packages/xrpl/test/fixtures/requests/index.ts index 7fd12ea0e8..3b458448bf 100644 --- a/packages/xrpl/test/fixtures/requests/index.ts +++ b/packages/xrpl/test/fixtures/requests/index.ts @@ -7,12 +7,14 @@ import signAsSign from './signAs.json' import escrowSign from './signEscrow.json' import signPaymentChannelClaim from './signPaymentChannelClaim.json' import ticketSign from './signTicket.json' +import signAsCustomDefinition from './signAsCustomDefinition.json' const sign = { normal: normalSign, ticket: ticketSign, escrow: escrowSign, signAs: signAsSign, + signAsCustomDefinition, } const getOrderbook = { diff --git a/packages/xrpl/test/fixtures/requests/signAsCustomDefinition.json b/packages/xrpl/test/fixtures/requests/signAsCustomDefinition.json new file mode 100644 index 0000000000..4320461bab --- /dev/null +++ b/packages/xrpl/test/fixtures/requests/signAsCustomDefinition.json @@ -0,0 +1,19 @@ +{ + "Account": "rEuLyBCvcw4CFmzv8RepSiAoNgF8tTGJQC", + "TransactionType": "TokenSwapPropose", + "AccountOther": "rJyZ28c179hKg7Gwt4P2S8zgzUTmMUMmzs", + "Expiration": 773819038, + "Flags": 2147483648, + "Sequence": 33626, + "Fee": "10", + "Amount": { + "currency": "AAA", + "issuer": "rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT", + "value": "1" + }, + "AmountOther": { + "currency": "BBB", + "issuer": "rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT", + "value": "1" + } +} diff --git a/packages/xrpl/test/fixtures/responses/index.ts b/packages/xrpl/test/fixtures/responses/index.ts index 5ffffae009..ae3d5ee610 100644 --- a/packages/xrpl/test/fixtures/responses/index.ts +++ b/packages/xrpl/test/fixtures/responses/index.ts @@ -11,6 +11,8 @@ import signAsSign from './signAs.json' import escrowSign from './signEscrow.json' import signPaymentChannelClaim from './signPaymentChannelClaim.json' import ticketSign from './signTicket.json' +import signCustomDefinition from './signCustomDefinition.json' +import signAsCustomDefinition from './signAsCustomDefinition.json' const getOrderbook = { normal: normalOrderBook, @@ -26,6 +28,8 @@ const sign = { ticket: ticketSign, escrow: escrowSign, signAs: signAsSign, + signCustomDefinition, + signAsCustomDefinition, } const responses = { diff --git a/packages/xrpl/test/fixtures/responses/signAsCustomDefinition.json b/packages/xrpl/test/fixtures/responses/signAsCustomDefinition.json new file mode 100644 index 0000000000..490e49ad5c --- /dev/null +++ b/packages/xrpl/test/fixtures/responses/signAsCustomDefinition.json @@ -0,0 +1,4 @@ +{ + "signedTransaction": "1200352280000000240000835A2A2E1F8A9E61D4838D7EA4C6800000000000000000000000000041414100000000008AEEEBA80624759E48F732403D7C70D591BB3D0A68400000000000000A6033D4838D7EA4C6800000000000000000000000000042424200000000008AEEEBA80624759E48F732403D7C70D591BB3D0A73008114A3780F5CB5A44D366520FC44055E8ED44D9A2270803414C52CA1760EA5FAB5DEA0092688910C2A47F73E28F3E010732102A8A44DB3D4C73EEEE11DFE54D2029103B776AA8A8D293A91D645977C9DF5F54474473045022100DEDDC3681C21A419CD05D7EA9D43B0EC12EB73A89EBB375B34E962340491D9E60220269D176AACB31B59B1E749CF3F642B77F76C3C2185B9BC0CA3C45712A060788C8114B3263BD0A9BF9DFDBBBBD07F536355FF477BF0E9E1F1", + "id": "3062208655FA2581C9465197015E1FB3FB3BA2BF47323F8D1516ECF62AF3BA45" +} diff --git a/packages/xrpl/test/fixtures/responses/signCustomDefinition.json b/packages/xrpl/test/fixtures/responses/signCustomDefinition.json new file mode 100644 index 0000000000..f4575e5831 --- /dev/null +++ b/packages/xrpl/test/fixtures/responses/signCustomDefinition.json @@ -0,0 +1,4 @@ +{ + "signedTransaction": "1200352280000000240000835A2A2E1F8A9E61D4838D7EA4C6800000000000000000000000000041414100000000008AEEEBA80624759E48F732403D7C70D591BB3D0A68400000000000000A6033D4838D7EA4C6800000000000000000000000000042424200000000008AEEEBA80624759E48F732403D7C70D591BB3D0A732102A8A44DB3D4C73EEEE11DFE54D2029103B776AA8A8D293A91D645977C9DF5F5447446304402205849DD6E2B936C955C6ECA847ACF7BF74DC363E572001E7FFA16DC0095244A0F02201B27BBA3992FDB0A8ADC24DFEF25AE4C2886786C0D290E8DE65618568E0F4F898114B3263BD0A9BF9DFDBBBBD07F536355FF477BF0E9803414C52CA1760EA5FAB5DEA0092688910C2A47F73E28", + "id": "A8F2FD97564CA3C15A184A2149EB8FDD32D1C14E6251E9892A4D4B2EC2E6D54C" +} diff --git a/packages/xrpl/test/fixtures/rippled/customDefinition.json b/packages/xrpl/test/fixtures/rippled/customDefinition.json new file mode 100644 index 0000000000..6619cac615 --- /dev/null +++ b/packages/xrpl/test/fixtures/rippled/customDefinition.json @@ -0,0 +1,3002 @@ +{ + "FIELDS": [ + [ + "Generic", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 0, + "type": "Unknown" + } + ], + [ + "Invalid", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": -1, + "type": "Unknown" + } + ], + [ + "ObjectEndMarker", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "STObject" + } + ], + [ + "ArrayEndMarker", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "STArray" + } + ], + [ + "taker_gets_funded", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 258, + "type": "Amount" + } + ], + [ + "taker_pays_funded", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 259, + "type": "Amount" + } + ], + [ + "LedgerEntryType", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "UInt16" + } + ], + [ + "TransactionType", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "UInt16" + } + ], + [ + "SignerWeight", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "UInt16" + } + ], + [ + "TransferFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "UInt16" + } + ], + [ + "TradingFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "UInt16" + } + ], + [ + "DiscountedFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "UInt16" + } + ], + [ + "Version", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "UInt16" + } + ], + [ + "HookStateChangeCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "UInt16" + } + ], + [ + "HookEmitCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "UInt16" + } + ], + [ + "HookExecutionIndex", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "UInt16" + } + ], + [ + "HookApiVersion", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 20, + "type": "UInt16" + } + ], + [ + "NetworkID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "UInt32" + } + ], + [ + "Flags", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "UInt32" + } + ], + [ + "SourceTag", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "UInt32" + } + ], + [ + "Sequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "UInt32" + } + ], + [ + "PreviousTxnLgrSeq", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "UInt32" + } + ], + [ + "LedgerSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "UInt32" + } + ], + [ + "CloseTime", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "UInt32" + } + ], + [ + "ParentCloseTime", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "UInt32" + } + ], + [ + "SigningTime", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "UInt32" + } + ], + [ + "Expiration", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "UInt32" + } + ], + [ + "TransferRate", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "UInt32" + } + ], + [ + "WalletSize", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "UInt32" + } + ], + [ + "OwnerCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 13, + "type": "UInt32" + } + ], + [ + "DestinationTag", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 14, + "type": "UInt32" + } + ], + [ + "LastUpdateTime", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 15, + "type": "UInt32" + } + ], + [ + "HighQualityIn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "UInt32" + } + ], + [ + "HighQualityOut", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "UInt32" + } + ], + [ + "LowQualityIn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "UInt32" + } + ], + [ + "LowQualityOut", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "UInt32" + } + ], + [ + "QualityIn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 20, + "type": "UInt32" + } + ], + [ + "QualityOut", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 21, + "type": "UInt32" + } + ], + [ + "StampEscrow", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "UInt32" + } + ], + [ + "BondAmount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 23, + "type": "UInt32" + } + ], + [ + "LoadFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 24, + "type": "UInt32" + } + ], + [ + "OfferSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 25, + "type": "UInt32" + } + ], + [ + "FirstLedgerSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 26, + "type": "UInt32" + } + ], + [ + "LastLedgerSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 27, + "type": "UInt32" + } + ], + [ + "TransactionIndex", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 28, + "type": "UInt32" + } + ], + [ + "OperationLimit", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 29, + "type": "UInt32" + } + ], + [ + "ReferenceFeeUnits", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 30, + "type": "UInt32" + } + ], + [ + "ReserveBase", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 31, + "type": "UInt32" + } + ], + [ + "ReserveIncrement", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 32, + "type": "UInt32" + } + ], + [ + "SetFlag", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 33, + "type": "UInt32" + } + ], + [ + "ClearFlag", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 34, + "type": "UInt32" + } + ], + [ + "SignerQuorum", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 35, + "type": "UInt32" + } + ], + [ + "CancelAfter", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 36, + "type": "UInt32" + } + ], + [ + "FinishAfter", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 37, + "type": "UInt32" + } + ], + [ + "SignerListID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 38, + "type": "UInt32" + } + ], + [ + "SettleDelay", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 39, + "type": "UInt32" + } + ], + [ + "TicketCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 40, + "type": "UInt32" + } + ], + [ + "TicketSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 41, + "type": "UInt32" + } + ], + [ + "NFTokenTaxon", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 42, + "type": "UInt32" + } + ], + [ + "MintedNFTokens", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 43, + "type": "UInt32" + } + ], + [ + "BurnedNFTokens", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 44, + "type": "UInt32" + } + ], + [ + "HookStateCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 45, + "type": "UInt32" + } + ], + [ + "EmitGeneration", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 46, + "type": "UInt32" + } + ], + [ + "VoteWeight", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 48, + "type": "UInt32" + } + ], + [ + "FirstNFTokenSequence", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 50, + "type": "UInt32" + } + ], + [ + "OracleDocumentID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 51, + "type": "UInt32" + } + ], + [ + "IndexNext", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "UInt64" + } + ], + [ + "IndexPrevious", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "UInt64" + } + ], + [ + "BookNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "UInt64" + } + ], + [ + "OwnerNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "UInt64" + } + ], + [ + "BaseFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "UInt64" + } + ], + [ + "ExchangeRate", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "UInt64" + } + ], + [ + "LowNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "UInt64" + } + ], + [ + "HighNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "UInt64" + } + ], + [ + "DestinationNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "UInt64" + } + ], + [ + "Cookie", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "UInt64" + } + ], + [ + "ServerVersion", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "UInt64" + } + ], + [ + "NFTokenOfferNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "UInt64" + } + ], + [ + "EmitBurden", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 13, + "type": "UInt64" + } + ], + [ + "HookOn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "UInt64" + } + ], + [ + "HookInstructionCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "UInt64" + } + ], + [ + "HookReturnCode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "UInt64" + } + ], + [ + "ReferenceCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "UInt64" + } + ], + [ + "XChainClaimID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 20, + "type": "UInt64" + } + ], + [ + "XChainAccountCreateCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 21, + "type": "UInt64" + } + ], + [ + "XChainAccountClaimCount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "UInt64" + } + ], + [ + "AssetPrice", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 23, + "type": "UInt64" + } + ], + [ + "TokenSwapId", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 53, + "type": "UInt64" + } + ], + [ + "EmailHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Hash128" + } + ], + [ + "LedgerHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Hash256" + } + ], + [ + "ParentHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Hash256" + } + ], + [ + "TransactionHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Hash256" + } + ], + [ + "AccountHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Hash256" + } + ], + [ + "PreviousTxnID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "Hash256" + } + ], + [ + "LedgerIndex", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "Hash256" + } + ], + [ + "WalletLocator", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "Hash256" + } + ], + [ + "RootIndex", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "Hash256" + } + ], + [ + "AccountTxnID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "Hash256" + } + ], + [ + "NFTokenID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "Hash256" + } + ], + [ + "EmitParentTxnID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "Hash256" + } + ], + [ + "EmitNonce", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "Hash256" + } + ], + [ + "EmitHookHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 13, + "type": "Hash256" + } + ], + [ + "AMMID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 14, + "type": "Hash256" + } + ], + [ + "BookDirectory", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "Hash256" + } + ], + [ + "InvoiceID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "Hash256" + } + ], + [ + "Nickname", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "Hash256" + } + ], + [ + "Amendment", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "Hash256" + } + ], + [ + "Digest", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 21, + "type": "Hash256" + } + ], + [ + "Channel", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "Hash256" + } + ], + [ + "ConsensusHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 23, + "type": "Hash256" + } + ], + [ + "CheckID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 24, + "type": "Hash256" + } + ], + [ + "ValidatedHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 25, + "type": "Hash256" + } + ], + [ + "PreviousPageMin", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 26, + "type": "Hash256" + } + ], + [ + "NextPageMin", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 27, + "type": "Hash256" + } + ], + [ + "NFTokenBuyOffer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 28, + "type": "Hash256" + } + ], + [ + "NFTokenSellOffer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 29, + "type": "Hash256" + } + ], + [ + "HookStateKey", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 30, + "type": "Hash256" + } + ], + [ + "HookHash", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 31, + "type": "Hash256" + } + ], + [ + "HookNamespace", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 32, + "type": "Hash256" + } + ], + [ + "HookSetTxnID", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 33, + "type": "Hash256" + } + ], + [ + "hash", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Hash256" + } + ], + [ + "index", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 258, + "type": "Hash256" + } + ], + [ + "Amount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Amount" + } + ], + [ + "Balance", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Amount" + } + ], + [ + "LimitAmount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Amount" + } + ], + [ + "TakerPays", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Amount" + } + ], + [ + "TakerGets", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "Amount" + } + ], + [ + "LowLimit", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "Amount" + } + ], + [ + "HighLimit", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "Amount" + } + ], + [ + "Fee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "Amount" + } + ], + [ + "SendMax", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "Amount" + } + ], + [ + "DeliverMin", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "Amount" + } + ], + [ + "Amount2", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "Amount" + } + ], + [ + "BidMin", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "Amount" + } + ], + [ + "BidMax", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 13, + "type": "Amount" + } + ], + [ + "MinimumOffer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "Amount" + } + ], + [ + "RippleEscrow", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "Amount" + } + ], + [ + "DeliveredAmount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "Amount" + } + ], + [ + "NFTokenBrokerFee", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "Amount" + } + ], + [ + "BaseFeeDrops", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "Amount" + } + ], + [ + "ReserveBaseDrops", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 23, + "type": "Amount" + } + ], + [ + "ReserveIncrementDrops", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 24, + "type": "Amount" + } + ], + [ + "LPTokenOut", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 25, + "type": "Amount" + } + ], + [ + "LPTokenIn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 26, + "type": "Amount" + } + ], + [ + "EPrice", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 27, + "type": "Amount" + } + ], + [ + "Price", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 28, + "type": "Amount" + } + ], + [ + "SignatureReward", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 29, + "type": "Amount" + } + ], + [ + "MinAccountCreateAmount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 30, + "type": "Amount" + } + ], + [ + "LPTokenBalance", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 31, + "type": "Amount" + } + ], + [ + "AmountOther", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 51, + "type": "Amount" + } + ], + [ + "PublicKey", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 1, + "type": "Blob" + } + ], + [ + "MessageKey", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 2, + "type": "Blob" + } + ], + [ + "SigningPubKey", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 3, + "type": "Blob" + } + ], + [ + "TxnSignature", + { + "isSerialized": true, + "isSigningField": false, + "isVLEncoded": true, + "nth": 4, + "type": "Blob" + } + ], + [ + "URI", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 5, + "type": "Blob" + } + ], + [ + "Signature", + { + "isSerialized": true, + "isSigningField": false, + "isVLEncoded": true, + "nth": 6, + "type": "Blob" + } + ], + [ + "Domain", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 7, + "type": "Blob" + } + ], + [ + "FundCode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 8, + "type": "Blob" + } + ], + [ + "RemoveCode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 9, + "type": "Blob" + } + ], + [ + "ExpireCode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 10, + "type": "Blob" + } + ], + [ + "CreateCode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 11, + "type": "Blob" + } + ], + [ + "MemoType", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 12, + "type": "Blob" + } + ], + [ + "MemoData", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 13, + "type": "Blob" + } + ], + [ + "MemoFormat", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 14, + "type": "Blob" + } + ], + [ + "Fulfillment", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 16, + "type": "Blob" + } + ], + [ + "Condition", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 17, + "type": "Blob" + } + ], + [ + "MasterSignature", + { + "isSerialized": true, + "isSigningField": false, + "isVLEncoded": true, + "nth": 18, + "type": "Blob" + } + ], + [ + "UNLModifyValidator", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 19, + "type": "Blob" + } + ], + [ + "ValidatorToDisable", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 20, + "type": "Blob" + } + ], + [ + "ValidatorToReEnable", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 21, + "type": "Blob" + } + ], + [ + "HookStateData", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 22, + "type": "Blob" + } + ], + [ + "HookReturnString", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 23, + "type": "Blob" + } + ], + [ + "HookParameterName", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 24, + "type": "Blob" + } + ], + [ + "HookParameterValue", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 25, + "type": "Blob" + } + ], + [ + "DIDDocument", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 26, + "type": "Blob" + } + ], + [ + "Data", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 27, + "type": "Blob" + } + ], + [ + "AssetClass", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 28, + "type": "Blob" + } + ], + [ + "Provider", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 29, + "type": "Blob" + } + ], + [ + "Account", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 1, + "type": "AccountID" + } + ], + [ + "Owner", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 2, + "type": "AccountID" + } + ], + [ + "Destination", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 3, + "type": "AccountID" + } + ], + [ + "Issuer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 4, + "type": "AccountID" + } + ], + [ + "Authorize", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 5, + "type": "AccountID" + } + ], + [ + "Unauthorize", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 6, + "type": "AccountID" + } + ], + [ + "RegularKey", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 8, + "type": "AccountID" + } + ], + [ + "NFTokenMinter", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 9, + "type": "AccountID" + } + ], + [ + "EmitCallback", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 10, + "type": "AccountID" + } + ], + [ + "HookAccount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 16, + "type": "AccountID" + } + ], + [ + "OtherChainSource", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 18, + "type": "AccountID" + } + ], + [ + "OtherChainDestination", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 19, + "type": "AccountID" + } + ], + [ + "AttestationSignerAccount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 20, + "type": "AccountID" + } + ], + [ + "AttestationRewardAccount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 21, + "type": "AccountID" + } + ], + [ + "LockingChainDoor", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 22, + "type": "AccountID" + } + ], + [ + "IssuingChainDoor", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 23, + "type": "AccountID" + } + ], + [ + "AccountOther", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 52, + "type": "AccountID" + } + ], + [ + "TransactionMetaData", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "STObject" + } + ], + [ + "CreatedNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "STObject" + } + ], + [ + "DeletedNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "STObject" + } + ], + [ + "ModifiedNode", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "STObject" + } + ], + [ + "PreviousFields", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "STObject" + } + ], + [ + "FinalFields", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "STObject" + } + ], + [ + "NewFields", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "STObject" + } + ], + [ + "TemplateEntry", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "STObject" + } + ], + [ + "Memo", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "STObject" + } + ], + [ + "SignerEntry", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "STObject" + } + ], + [ + "NFToken", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "STObject" + } + ], + [ + "EmitDetails", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 13, + "type": "STObject" + } + ], + [ + "Hook", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 14, + "type": "STObject" + } + ], + [ + "Signer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "STObject" + } + ], + [ + "Majority", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "STObject" + } + ], + [ + "DisabledValidator", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "STObject" + } + ], + [ + "EmittedTxn", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 20, + "type": "STObject" + } + ], + [ + "HookExecution", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 21, + "type": "STObject" + } + ], + [ + "HookDefinition", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "STObject" + } + ], + [ + "HookParameter", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 23, + "type": "STObject" + } + ], + [ + "HookGrant", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 24, + "type": "STObject" + } + ], + [ + "VoteEntry", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 25, + "type": "STObject" + } + ], + [ + "AuctionSlot", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 26, + "type": "STObject" + } + ], + [ + "AuthAccount", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 27, + "type": "STObject" + } + ], + [ + "XChainClaimProofSig", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 28, + "type": "STObject" + } + ], + [ + "XChainCreateAccountProofSig", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 29, + "type": "STObject" + } + ], + [ + "XChainClaimAttestationCollectionElement", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 30, + "type": "STObject" + } + ], + [ + "XChainCreateAccountAttestationCollectionElement", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 31, + "type": "STObject" + } + ], + [ + "PriceData", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 32, + "type": "STObject" + } + ], + [ + "Signers", + { + "isSerialized": true, + "isSigningField": false, + "isVLEncoded": false, + "nth": 3, + "type": "STArray" + } + ], + [ + "SignerEntries", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "STArray" + } + ], + [ + "Template", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 5, + "type": "STArray" + } + ], + [ + "Necessary", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 6, + "type": "STArray" + } + ], + [ + "Sufficient", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 7, + "type": "STArray" + } + ], + [ + "AffectedNodes", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 8, + "type": "STArray" + } + ], + [ + "Memos", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 9, + "type": "STArray" + } + ], + [ + "NFTokens", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 10, + "type": "STArray" + } + ], + [ + "Hooks", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 11, + "type": "STArray" + } + ], + [ + "VoteSlots", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 12, + "type": "STArray" + } + ], + [ + "Majorities", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "STArray" + } + ], + [ + "DisabledValidators", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "STArray" + } + ], + [ + "HookExecutions", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "STArray" + } + ], + [ + "HookParameters", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "STArray" + } + ], + [ + "HookGrants", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 20, + "type": "STArray" + } + ], + [ + "XChainClaimAttestations", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 21, + "type": "STArray" + } + ], + [ + "XChainCreateAccountAttestations", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 22, + "type": "STArray" + } + ], + [ + "PriceDataSeries", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 24, + "type": "STArray" + } + ], + [ + "AuthAccounts", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 25, + "type": "STArray" + } + ], + [ + "CloseResolution", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "UInt8" + } + ], + [ + "Method", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "UInt8" + } + ], + [ + "TransactionResult", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "UInt8" + } + ], + [ + "Scale", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "UInt8" + } + ], + [ + "TickSize", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 16, + "type": "UInt8" + } + ], + [ + "UNLModifyDisabling", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 17, + "type": "UInt8" + } + ], + [ + "HookResult", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 18, + "type": "UInt8" + } + ], + [ + "WasLockingChainSend", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 19, + "type": "UInt8" + } + ], + [ + "TakerPaysCurrency", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Hash160" + } + ], + [ + "TakerPaysIssuer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Hash160" + } + ], + [ + "TakerGetsCurrency", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Hash160" + } + ], + [ + "TakerGetsIssuer", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Hash160" + } + ], + [ + "Paths", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "PathSet" + } + ], + [ + "Indexes", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 1, + "type": "Vector256" + } + ], + [ + "Hashes", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 2, + "type": "Vector256" + } + ], + [ + "Amendments", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 3, + "type": "Vector256" + } + ], + [ + "NFTokenOffers", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": true, + "nth": 4, + "type": "Vector256" + } + ], + [ + "LockingChainIssue", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Issue" + } + ], + [ + "IssuingChainIssue", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Issue" + } + ], + [ + "Asset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 3, + "type": "Issue" + } + ], + [ + "Asset2", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 4, + "type": "Issue" + } + ], + [ + "XChainBridge", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "XChainBridge" + } + ], + [ + "BaseAsset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 1, + "type": "Currency" + } + ], + [ + "QuoteAsset", + { + "isSerialized": true, + "isSigningField": true, + "isVLEncoded": false, + "nth": 2, + "type": "Currency" + } + ], + [ + "Transaction", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Transaction" + } + ], + [ + "LedgerEntry", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "LedgerEntry" + } + ], + [ + "Validation", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Validation" + } + ], + [ + "Metadata", + { + "isSerialized": false, + "isSigningField": false, + "isVLEncoded": false, + "nth": 257, + "type": "Metadata" + } + ] + ], + "LEDGER_ENTRY_TYPES": { + "AMM": 121, + "AccountRoot": 97, + "Amendments": 102, + "Bridge": 105, + "Check": 67, + "DID": 73, + "DepositPreauth": 112, + "DirectoryNode": 100, + "Escrow": 117, + "FeeSettings": 115, + "Invalid": -1, + "LedgerHashes": 104, + "NFTokenOffer": 55, + "NFTokenPage": 80, + "NegativeUNL": 78, + "Offer": 111, + "Oracle": 128, + "PayChannel": 120, + "RippleState": 114, + "SignerList": 83, + "Ticket": 84, + "TokenSwap": 119, + "XChainOwnedClaimID": 113, + "XChainOwnedCreateAccountClaimID": 116 + }, + "TRANSACTION_RESULTS": { + "tecAMM_ACCOUNT": 168, + "tecAMM_BALANCE": 163, + "tecAMM_EMPTY": 166, + "tecAMM_FAILED": 164, + "tecAMM_INVALID_TOKENS": 165, + "tecAMM_NOT_EMPTY": 167, + "tecARRAY_EMPTY": 190, + "tecARRAY_TOO_LARGE": 191, + "tecCANT_ACCEPT_OWN_NFTOKEN_OFFER": 158, + "tecCLAIM": 100, + "tecCRYPTOCONDITION_ERROR": 146, + "tecDIR_FULL": 121, + "tecDST_TAG_NEEDED": 143, + "tecDUPLICATE": 149, + "tecEMPTY_DID": 187, + "tecEXPIRED": 148, + "tecFAILED_PROCESSING": 105, + "tecFROZEN": 137, + "tecHAS_OBLIGATIONS": 151, + "tecINCOMPLETE": 169, + "tecINSUFFICIENT_FUNDS": 159, + "tecINSUFFICIENT_PAYMENT": 161, + "tecINSUFFICIENT_RESERVE": 141, + "tecINSUFF_FEE": 136, + "tecINSUF_RESERVE_LINE": 122, + "tecINSUF_RESERVE_OFFER": 123, + "tecINTERNAL": 144, + "tecINVALID_UPDATE_TIME": 188, + "tecINVARIANT_FAILED": 147, + "tecKILLED": 150, + "tecMAX_SEQUENCE_REACHED": 154, + "tecNEED_MASTER_KEY": 142, + "tecNFTOKEN_BUY_SELL_MISMATCH": 156, + "tecNFTOKEN_OFFER_TYPE_MISMATCH": 157, + "tecNO_ALTERNATIVE_KEY": 130, + "tecNO_AUTH": 134, + "tecNO_DST": 124, + "tecNO_DST_INSUF_XRP": 125, + "tecNO_ENTRY": 140, + "tecNO_ISSUER": 133, + "tecNO_LINE": 135, + "tecNO_LINE_INSUF_RESERVE": 126, + "tecNO_LINE_REDUNDANT": 127, + "tecNO_PERMISSION": 139, + "tecNO_REGULAR_KEY": 131, + "tecNO_SUITABLE_NFTOKEN_PAGE": 155, + "tecNO_TARGET": 138, + "tecOBJECT_NOT_FOUND": 160, + "tecOVERSIZE": 145, + "tecOWNERS": 132, + "tecPATH_DRY": 128, + "tecPATH_PARTIAL": 101, + "tecTOKEN_PAIR_NOT_FOUND": 189, + "tecTOO_SOON": 152, + "tecUNFUNDED": 129, + "tecUNFUNDED_ADD": 102, + "tecUNFUNDED_AMM": 162, + "tecUNFUNDED_OFFER": 103, + "tecUNFUNDED_PAYMENT": 104, + "tecXCHAIN_ACCOUNT_CREATE_PAST": 181, + "tecXCHAIN_ACCOUNT_CREATE_TOO_MANY": 182, + "tecXCHAIN_BAD_CLAIM_ID": 172, + "tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR": 185, + "tecXCHAIN_BAD_TRANSFER_ISSUE": 170, + "tecXCHAIN_CLAIM_NO_QUORUM": 173, + "tecXCHAIN_CREATE_ACCOUNT_DISABLED": 186, + "tecXCHAIN_CREATE_ACCOUNT_NONXRP_ISSUE": 175, + "tecXCHAIN_INSUFF_CREATE_AMOUNT": 180, + "tecXCHAIN_NO_CLAIM_ID": 171, + "tecXCHAIN_NO_SIGNERS_LIST": 178, + "tecXCHAIN_PAYMENT_FAILED": 183, + "tecXCHAIN_PROOF_UNKNOWN_KEY": 174, + "tecXCHAIN_REWARD_MISMATCH": 177, + "tecXCHAIN_SELF_COMMIT": 184, + "tecXCHAIN_SENDING_ACCOUNT_MISMATCH": 179, + "tecXCHAIN_WRONG_CHAIN": 176, + "tefALREADY": -198, + "tefBAD_ADD_AUTH": -197, + "tefBAD_AUTH": -196, + "tefBAD_AUTH_MASTER": -183, + "tefBAD_LEDGER": -195, + "tefBAD_QUORUM": -185, + "tefBAD_SIGNATURE": -186, + "tefCREATED": -194, + "tefEXCEPTION": -193, + "tefFAILURE": -199, + "tefINTERNAL": -192, + "tefINVARIANT_FAILED": -182, + "tefMASTER_DISABLED": -188, + "tefMAX_LEDGER": -187, + "tefNFTOKEN_IS_NOT_TRANSFERABLE": -179, + "tefNOT_MULTI_SIGNING": -184, + "tefNO_AUTH_REQUIRED": -191, + "tefNO_TICKET": -180, + "tefPAST_SEQ": -190, + "tefTOO_BIG": -181, + "tefWRONG_PRIOR": -189, + "telBAD_DOMAIN": -398, + "telBAD_PATH_COUNT": -397, + "telBAD_PUBLIC_KEY": -396, + "telCAN_NOT_QUEUE": -392, + "telCAN_NOT_QUEUE_BALANCE": -391, + "telCAN_NOT_QUEUE_BLOCKED": -389, + "telCAN_NOT_QUEUE_BLOCKS": -390, + "telCAN_NOT_QUEUE_FEE": -388, + "telCAN_NOT_QUEUE_FULL": -387, + "telENV_RPC_FAILED": -383, + "telFAILED_PROCESSING": -395, + "telINSUF_FEE_P": -394, + "telLOCAL_ERROR": -399, + "telNETWORK_ID_MAKES_TX_NON_CANONICAL": -384, + "telNO_DST_PARTIAL": -393, + "telREQUIRES_NETWORK_ID": -385, + "telWRONG_NETWORK": -386, + "temARRAY_EMPTY": -253, + "temARRAY_TOO_LARGE": -252, + "temBAD_AMM_TOKENS": -261, + "temBAD_AMOUNT": -298, + "temBAD_CURRENCY": -297, + "temBAD_EXPIRATION": -296, + "temBAD_FEE": -295, + "temBAD_ISSUER": -294, + "temBAD_LIMIT": -293, + "temBAD_NFTOKEN_TRANSFER_FEE": -262, + "temBAD_OFFER": -292, + "temBAD_PATH": -291, + "temBAD_PATH_LOOP": -290, + "temBAD_QUORUM": -271, + "temBAD_REGKEY": -289, + "temBAD_SEND_XRP_LIMIT": -288, + "temBAD_SEND_XRP_MAX": -287, + "temBAD_SEND_XRP_NO_DIRECT": -286, + "temBAD_SEND_XRP_PARTIAL": -285, + "temBAD_SEND_XRP_PATHS": -284, + "temBAD_SEQUENCE": -283, + "temBAD_SIGNATURE": -282, + "temBAD_SIGNER": -272, + "temBAD_SRC_ACCOUNT": -281, + "temBAD_TICK_SIZE": -269, + "temBAD_TRANSFER_RATE": -280, + "temBAD_WEIGHT": -270, + "temCANNOT_PREAUTH_SELF": -267, + "temDISABLED": -273, + "temDST_IS_SRC": -279, + "temDST_NEEDED": -278, + "temEMPTY_DID": -254, + "temINVALID": -277, + "temINVALID_ACCOUNT_ID": -268, + "temINVALID_COUNT": -266, + "temINVALID_FLAG": -276, + "temINVALID_TOKEN_SWAP_ID": -333, + "temMALFORMED": -299, + "temREDUNDANT": -275, + "temRIPPLE_EMPTY": -274, + "temSEQ_AND_TICKET": -263, + "temUNCERTAIN": -265, + "temUNKNOWN": -264, + "temXCHAIN_BAD_PROOF": -259, + "temXCHAIN_BRIDGE_BAD_ISSUES": -258, + "temXCHAIN_BRIDGE_BAD_MIN_ACCOUNT_CREATE_AMOUNT": -256, + "temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT": -255, + "temXCHAIN_BRIDGE_NONDOOR_OWNER": -257, + "temXCHAIN_EQUAL_DOOR_ACCOUNTS": -260, + "terFUNDS_SPENT": -98, + "terINSUF_FEE_B": -97, + "terLAST": -91, + "terNO_ACCOUNT": -96, + "terNO_AMM": -87, + "terNO_AUTH": -95, + "terNO_LINE": -94, + "terNO_RIPPLE": -90, + "terOWNERS": -93, + "terPRE_SEQ": -92, + "terPRE_TICKET": -88, + "terQUEUED": -89, + "terRETRY": -99, + "tesSUCCESS": 0 + }, + "TRANSACTION_TYPES": { + "AMMBid": 39, + "AMMCreate": 35, + "AMMDelete": 40, + "AMMDeposit": 36, + "AMMVote": 38, + "AMMWithdraw": 37, + "AccountDelete": 21, + "AccountSet": 3, + "CheckCancel": 18, + "CheckCash": 17, + "CheckCreate": 16, + "Clawback": 30, + "DIDDelete": 50, + "DIDSet": 49, + "DepositPreauth": 19, + "EnableAmendment": 100, + "EscrowCancel": 4, + "EscrowCreate": 1, + "EscrowFinish": 2, + "Invalid": -1, + "NFTokenAcceptOffer": 29, + "NFTokenBurn": 26, + "NFTokenCancelOffer": 28, + "NFTokenCreateOffer": 27, + "NFTokenMint": 25, + "OfferCancel": 8, + "OfferCreate": 7, + "OracleDelete": 52, + "OracleSet": 51, + "Payment": 0, + "PaymentChannelClaim": 15, + "PaymentChannelCreate": 13, + "PaymentChannelFund": 14, + "SetFee": 101, + "SetRegularKey": 5, + "SignerListSet": 12, + "TicketCreate": 10, + "TokenSwapAccept": 54, + "TokenSwapPropose": 53, + "TrustSet": 20, + "UNLModify": 102, + "XChainAccountCreateCommit": 44, + "XChainAddAccountCreateAttestation": 46, + "XChainAddClaimAttestation": 45, + "XChainClaim": 43, + "XChainCommit": 42, + "XChainCreateBridge": 48, + "XChainCreateClaimID": 41, + "XChainModifyBridge": 47 + }, + "TYPES": { + "AccountID": 8, + "Amount": 6, + "Blob": 7, + "Currency": 26, + "Done": -1, + "Hash128": 4, + "Hash160": 17, + "Hash256": 5, + "Issue": 24, + "LedgerEntry": 10002, + "Metadata": 10004, + "NotPresent": 0, + "PathSet": 18, + "STArray": 15, + "STObject": 14, + "Transaction": 10001, + "UInt16": 1, + "UInt192": 21, + "UInt32": 2, + "UInt384": 22, + "UInt512": 23, + "UInt64": 3, + "UInt8": 16, + "UInt96": 20, + "Unknown": -2, + "Validation": 10003, + "Vector256": 19, + "XChainBridge": 25 + }, + "hash": "6D184848F67345A6A6AA0386A174C8ECE596B17DCFD9638F0CF09FF16611F49F", + "status": "success" +} diff --git a/packages/xrpl/test/fixtures/rippled/index.ts b/packages/xrpl/test/fixtures/rippled/index.ts index f8b4382d19..3aefe2a695 100644 --- a/packages/xrpl/test/fixtures/rippled/index.ts +++ b/packages/xrpl/test/fixtures/rippled/index.ts @@ -33,6 +33,7 @@ import Payment from './tx/payment.json' import XChainCreateClaimID from './tx/XChainCreateClaimID.json' import XChainCreateClaimID2 from './tx/XChainCreateClaimID2.json' import unsubscribe from './unsubscribe.json' +import customDefinition from './customDefinition.json' const submit = { success: successSubmit, @@ -94,6 +95,10 @@ const server_info = { withNetworkId: withNetworkIDServerInfo, } +const definitions = { + customDefinition, +} + const tx = { NFTokenMint, NFTokenMint2, @@ -118,6 +123,7 @@ const rippled = { transaction_entry, tx, unsubscribe, + definitions, } export default rippled diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index bbb454108f..62c128298e 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -1,5 +1,5 @@ import { assert } from 'chai' -import { decode } from 'ripple-binary-codec' +import { XrplDefinitions, decode } from 'ripple-binary-codec' import { NFTokenMint, @@ -11,6 +11,7 @@ import ECDSA from '../../src/ECDSA' import { Wallet } from '../../src/Wallet' import requests from '../fixtures/requests' import responses from '../fixtures/responses' +import rippled from '../fixtures/rippled' const { sign: REQUEST_FIXTURES } = requests const { sign: RESPONSE_FIXTURES } = responses @@ -1186,6 +1187,51 @@ describe('Wallet', function () { wallet.sign(tx) }, /URI must be in hex format/u) }) + + it('sign succeeds with a custom definition is passed', async function () { + const customDefinition = new XrplDefinitions( + rippled.definitions.customDefinition, + ) + const tx = { + Account: wallet.address, + TransactionType: 'TokenSwapPropose', + Flags: 2147483648, + Sequence: 33626, + Fee: '10', + AccountOther: 'rJyZ28c179hKg7Gwt4P2S8zgzUTmMUMmzs', + Expiration: 773819038, + Amount: { + currency: 'AAA', + issuer: 'rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT', + value: '1', + }, + AmountOther: { + currency: 'BBB', + issuer: 'rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT', + value: '1', + }, + } + const result = wallet.sign(tx as any, false, customDefinition) + assert.deepEqual(result, { + tx_blob: RESPONSE_FIXTURES.signCustomDefinition.signedTransaction, + hash: RESPONSE_FIXTURES.signCustomDefinition.id, + }) + }) + + it('multisign succeeds with a custom definition is passed', async function () { + const customDefinition = new XrplDefinitions( + rippled.definitions.customDefinition, + ) + const result = wallet.sign( + REQUEST_FIXTURES.signAsCustomDefinition as any, + true, + customDefinition, + ) + assert.deepEqual(result, { + tx_blob: RESPONSE_FIXTURES.signAsCustomDefinition.signedTransaction, + hash: RESPONSE_FIXTURES.signAsCustomDefinition.id, + }) + }) }) describe('verifyTransaction', function () { From b5291490c956000b1ee3aaaf5c43d7b5cd976969 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Tue, 23 Apr 2024 13:38:57 +0100 Subject: [PATCH 03/15] docs(history): xrpl history update --- packages/xrpl/HISTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index 7ff93a2f21..b3583ff487 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -13,6 +13,9 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr * Add missing `lsfAMMNode` flag to `RippleState` ledger object * Add `PreviousFields` to `DeletedNode` metadata type +### Added +* Custom definitions support for `util.encode`, `util.decode`, `util.encodeForSignning` and `Wallet.sign`. + ## 3.0.0 (2024-02-01) ### BREAKING CHANGES From a618fb9d3e67ed4e7ae77fb21eec2739ace6717e Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Tue, 23 Apr 2024 13:45:22 +0100 Subject: [PATCH 04/15] chore: maintain linebreak --- packages/ripple-binary-codec/src/types/amount.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ripple-binary-codec/src/types/amount.ts b/packages/ripple-binary-codec/src/types/amount.ts index 405770c5a8..b92ebf4fc2 100644 --- a/packages/ripple-binary-codec/src/types/amount.ts +++ b/packages/ripple-binary-codec/src/types/amount.ts @@ -123,6 +123,7 @@ class Amount extends SerializedType { const issuer = AccountID.from(value.issuer).toBytes() return new Amount(concat([amount, currency, issuer])) } + throw new Error('Invalid type to construct an Amount') } From b283fc321b901924857e0f3a2d7bb30e37114e38 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Tue, 23 Apr 2024 13:49:26 +0100 Subject: [PATCH 05/15] chore: keep source.fixAll.eslint value --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ef2c734c23..5dc2e1cf8e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,7 +39,7 @@ "enable": true }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "source.fixAll.eslint": true }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, From 4689b023cef0b7c49a2b83b16259cba8661ec0d7 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Tue, 23 Apr 2024 13:50:19 +0100 Subject: [PATCH 06/15] chore: typo --- packages/xrpl/test/wallet/index.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index 62c128298e..165a057c67 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -1188,7 +1188,7 @@ describe('Wallet', function () { }, /URI must be in hex format/u) }) - it('sign succeeds with a custom definition is passed', async function () { + it('sign succeeds when a custom definition is passed', async function () { const customDefinition = new XrplDefinitions( rippled.definitions.customDefinition, ) @@ -1218,7 +1218,7 @@ describe('Wallet', function () { }) }) - it('multisign succeeds with a custom definition is passed', async function () { + it('multisign succeeds when a custom definition is passed', async function () { const customDefinition = new XrplDefinitions( rippled.definitions.customDefinition, ) From 59c20741a44307164111e61d5178c26fe7f55ac9 Mon Sep 17 00:00:00 2001 From: elmurci Date: Tue, 7 May 2024 08:41:10 +0100 Subject: [PATCH 07/15] Update packages/xrpl/src/models/transactions/transaction.ts Co-authored-by: Mayukha Vadari --- packages/xrpl/src/models/transactions/transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 506d33efd5..b1e9eaba32 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -171,7 +171,7 @@ export interface TransactionAndMetadata< */ export function validate( transaction: Record, - customDefinition?: boolean, + hasCustomDefinition?: boolean, ): void { const tx = { ...transaction } if (tx.TransactionType == null) { From 6089035e1bd70b9e83de7da8698c4c5e8aada740 Mon Sep 17 00:00:00 2001 From: elmurci Date: Mon, 19 Aug 2024 15:34:14 +0100 Subject: [PATCH 08/15] Update packages/xrpl/src/models/transactions/transaction.ts Co-authored-by: tequ --- packages/xrpl/src/models/transactions/transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index b1e9eaba32..f80d10c008 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -398,7 +398,7 @@ export function validate( break default: - if (!customDefinition) + if (!hasCustomDefinition) throw new ValidationError( `Invalid field TransactionType: ${tx.TransactionType}`, ) From 7021e63498a127c3a55524390fea679a18504335 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 23 Aug 2024 19:01:00 +0900 Subject: [PATCH 09/15] Support custom definitions for `client.submit()`, `client.submitAndWait()` --- packages/xrpl/src/Wallet/index.ts | 5 +--- packages/xrpl/src/client/index.ts | 44 +++++++++++++++++++++++++++++-- packages/xrpl/src/sugar/submit.ts | 25 +++++++++++++----- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 0752938268..161db6da9f 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -409,10 +409,7 @@ export class Wallet { * This will throw a more clear error for JS users if the supplied transaction has incorrect formatting */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type - validate( - tx as unknown as Record, - definitions ? true : false, - ) + validate(tx as unknown as Record, Boolean(definitions)) const txToSignAndEncode = { ...tx } diff --git a/packages/xrpl/src/client/index.ts b/packages/xrpl/src/client/index.ts index 5d2c881592..27b1061068 100644 --- a/packages/xrpl/src/client/index.ts +++ b/packages/xrpl/src/client/index.ts @@ -2,6 +2,7 @@ /* eslint-disable max-lines -- Client is a large file w/ lots of imports/exports */ import { EventEmitter } from 'eventemitter3' +import { XrplDefinitionsBase } from 'ripple-binary-codec' import { RippledError, @@ -213,6 +214,12 @@ class Client extends EventEmitter { */ public buildVersion: string | undefined + /** + * Custom rippled types to use instead of the default. Used for sidechains and amendments. + * + */ + public definitions: XrplDefinitionsBase | undefined + /** * Creates a new Client with a websocket connection to a rippled server. * @@ -510,6 +517,33 @@ class Client extends EventEmitter { } } + /** + * Get Definitions from server_definitions + * + * @returns void + * @example + * ```ts + * const { Client } = require('xrpl') + * const client = new Client('wss://s.altnet.rippletest.net:51233') + * await client.getDefinitions() + * console.log(client.definitions) + * ``` + */ + public async getDefinitions(): Promise { + try { + const response = await this.request({ + command: 'server_definitions', + }) + this.definitions = new XrplDefinitionsBase( + JSON.parse(JSON.stringify(response.result)), + {}, + ) + } catch (error) { + // eslint-disable-next-line no-console -- Print the error to console but allows client to be connected. + console.error(error) + } + } + /** * Tells the Client instance to connect to its rippled server. * @@ -714,7 +748,10 @@ class Client extends EventEmitter { wallet?: Wallet }, ): Promise { - const signedTx = await getSignedTx(this, transaction, opts) + const signedTx = await getSignedTx(this, transaction, { + ...opts, + definitions: this.definitions, + }) return submitRequest(this, signedTx, opts?.failHard) } @@ -788,7 +825,10 @@ class Client extends EventEmitter { wallet?: Wallet }, ): Promise> { - const signedTx = await getSignedTx(this, transaction, opts) + const signedTx = await getSignedTx(this, transaction, { + ...opts, + definitions: this.definitions, + }) const lastLedger = getLastLedgerSequence(signedTx) if (lastLedger == null) { diff --git a/packages/xrpl/src/sugar/submit.ts b/packages/xrpl/src/sugar/submit.ts index ee5e0406f8..ef037ecb76 100644 --- a/packages/xrpl/src/sugar/submit.ts +++ b/packages/xrpl/src/sugar/submit.ts @@ -1,4 +1,4 @@ -import { decode, encode } from 'ripple-binary-codec' +import { decode, encode, XrplDefinitionsBase } from 'ripple-binary-codec' import type { Client, @@ -31,6 +31,7 @@ async function sleep(ms: number): Promise { * @param signedTransaction - The signed transaction to submit. It can be either a Transaction object or a * string (encode from ripple-binary-codec) representation of the transaction. * @param [failHard=false] - Optional. Determines whether the submission should fail hard (true) or not (false). Default is false. + * @param definitions - Optional. Custom rippled types to use instead of the default. Used for sidechains and amendments. * @returns A promise that resolves with the response from the client. * @throws {ValidationError} If the signed transaction is not valid (not signed). * @@ -46,12 +47,14 @@ async function sleep(ms: number): Promise { * const signedTransactionString = encode(signedTransaction); * const response2 = await submitRequest(client, signedTransactionString, true); */ +// eslint-disable-next-line max-params -- Needs 4 params export async function submitRequest( client: Client, signedTransaction: SubmittableTransaction | string, failHard = false, + definitions?: XrplDefinitionsBase, ): Promise { - if (!isSigned(signedTransaction)) { + if (!isSigned(signedTransaction, definitions)) { throw new ValidationError('Transaction must be signed') } @@ -165,8 +168,14 @@ export async function waitForFinalTransactionOutcome< } // checks if the transaction has been signed -function isSigned(transaction: SubmittableTransaction | string): boolean { - const tx = typeof transaction === 'string' ? decode(transaction) : transaction +function isSigned( + transaction: SubmittableTransaction | string, + definitions?: XrplDefinitionsBase, +): boolean { + const tx = + typeof transaction === 'string' + ? decode(transaction, definitions) + : transaction if (typeof tx === 'string') { return false } @@ -200,6 +209,8 @@ function isSigned(transaction: SubmittableTransaction | string): boolean { * or not (false). Default is true. * @param [options.wallet] - Optional. A wallet to sign the transaction. It must be provided when submitting * an unsigned transaction. Default is undefined. + * @param [options.definitions] - Optional. Custom rippled types to use instead of the default. + * Used for sidechains and amendments. Default is undefined. * @returns A promise that resolves with the signed transaction. * * @throws {ValidationError} If the transaction is not signed and no wallet is provided. @@ -228,14 +239,16 @@ export async function getSignedTx( { autofill = true, wallet, + definitions, }: { // If true, autofill a transaction. autofill?: boolean // A wallet to sign a transaction. It must be provided when submitting an unsigned transaction. wallet?: Wallet + definitions?: XrplDefinitionsBase } = {}, ): Promise { - if (isSigned(transaction)) { + if (isSigned(transaction, definitions)) { return transaction } @@ -248,7 +261,7 @@ export async function getSignedTx( let tx = typeof transaction === 'string' ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts JsonObject to correct Transaction type - (decode(transaction) as unknown as SubmittableTransaction) + (decode(transaction, definitions) as unknown as SubmittableTransaction) : transaction if (autofill) { From 02a8503686cb5421ce0ebdcbd1bbe9f4b9cf6fe9 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 23 Aug 2024 19:02:26 +0900 Subject: [PATCH 10/15] fix some lint error --- packages/xrpl/src/models/transactions/transaction.ts | 4 +++- packages/xrpl/src/utils/hashes/hashLedger.ts | 1 + packages/xrpl/test/fixtures/requests/index.ts | 2 +- packages/xrpl/test/fixtures/responses/index.ts | 4 ++-- packages/xrpl/test/fixtures/rippled/index.ts | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index f80d10c008..ccb110a38d 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -166,6 +166,7 @@ export interface TransactionAndMetadata< * Encode/decode and individual type validation. * * @param transaction - A Transaction. + * @param hasCustomDefinition - Whether the transaction has a custom definition. * @throws ValidationError When the Transaction is malformed. * @category Utilities */ @@ -398,9 +399,10 @@ export function validate( break default: - if (!hasCustomDefinition) + if (!hasCustomDefinition) { throw new ValidationError( `Invalid field TransactionType: ${tx.TransactionType}`, ) + } } } diff --git a/packages/xrpl/src/utils/hashes/hashLedger.ts b/packages/xrpl/src/utils/hashes/hashLedger.ts index b6a7ea19a0..ad2ac81b3f 100644 --- a/packages/xrpl/src/utils/hashes/hashLedger.ts +++ b/packages/xrpl/src/utils/hashes/hashLedger.ts @@ -64,6 +64,7 @@ function addLengthPrefix(hex: string): string { * Hashes the Transaction object as the ledger does. Throws if the transaction is unsigned. * * @param tx - A transaction to hash. Tx may be in binary blob form. Tx must be signed. + * @param definitions - Definitions to use for encoding and decoding. * @returns A hash of tx. * @throws ValidationError if the Transaction is unsigned.\ * @category Utilities diff --git a/packages/xrpl/test/fixtures/requests/index.ts b/packages/xrpl/test/fixtures/requests/index.ts index 3b458448bf..63355856d7 100644 --- a/packages/xrpl/test/fixtures/requests/index.ts +++ b/packages/xrpl/test/fixtures/requests/index.ts @@ -4,10 +4,10 @@ import header from './hashLedger.json' import transactions from './hashLedgerTransactions.json' import normalSign from './sign.json' import signAsSign from './signAs.json' +import signAsCustomDefinition from './signAsCustomDefinition.json' import escrowSign from './signEscrow.json' import signPaymentChannelClaim from './signPaymentChannelClaim.json' import ticketSign from './signTicket.json' -import signAsCustomDefinition from './signAsCustomDefinition.json' const sign = { normal: normalSign, diff --git a/packages/xrpl/test/fixtures/responses/index.ts b/packages/xrpl/test/fixtures/responses/index.ts index ae3d5ee610..1c2c5db603 100644 --- a/packages/xrpl/test/fixtures/responses/index.ts +++ b/packages/xrpl/test/fixtures/responses/index.ts @@ -8,11 +8,11 @@ import withXRPOrderBook from './getOrderbookWithXrp.json' import getServerInfo from './getServerInfo.json' import normalSign from './sign.json' import signAsSign from './signAs.json' +import signAsCustomDefinition from './signAsCustomDefinition.json' +import signCustomDefinition from './signCustomDefinition.json' import escrowSign from './signEscrow.json' import signPaymentChannelClaim from './signPaymentChannelClaim.json' import ticketSign from './signTicket.json' -import signCustomDefinition from './signCustomDefinition.json' -import signAsCustomDefinition from './signAsCustomDefinition.json' const getOrderbook = { normal: normalOrderBook, diff --git a/packages/xrpl/test/fixtures/rippled/index.ts b/packages/xrpl/test/fixtures/rippled/index.ts index 3aefe2a695..213693eb46 100644 --- a/packages/xrpl/test/fixtures/rippled/index.ts +++ b/packages/xrpl/test/fixtures/rippled/index.ts @@ -5,6 +5,7 @@ import normalAccountTx from './accountTx.json' import fabric from './bookOffers' import usd_xrp from './bookOffersUsdXrp.json' import xrp_usd from './bookOffersXrpUsd.json' +import customDefinition from './customDefinition.json' import normalLedger from './ledger.json' import firstPage from './ledgerDataFirstPage.json' import firstPageEmpty from './ledgerDataFirstPageEmpty.json' @@ -33,7 +34,6 @@ import Payment from './tx/payment.json' import XChainCreateClaimID from './tx/XChainCreateClaimID.json' import XChainCreateClaimID2 from './tx/XChainCreateClaimID2.json' import unsubscribe from './unsubscribe.json' -import customDefinition from './customDefinition.json' const submit = { success: successSubmit, From b047f04ee39d0910b3404548a91f23a6fe3be93d Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Mon, 26 Aug 2024 13:26:24 +0100 Subject: [PATCH 11/15] feat: addresses https://github.com/XRPLF/xrpl.js/pull/2683#discussion_r1576698292 --- .vscode/settings.json | 2 +- packages/xrpl/src/Wallet/index.ts | 2 +- .../xrpl/src/models/transactions/common.ts | 20 ++++++++++++- .../src/models/transactions/transaction.ts | 16 ++++++++--- packages/xrpl/test/wallet/index.test.ts | 28 +++++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5dc2e1cf8e..ef2c734c23 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,7 +39,7 @@ "enable": true }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, diff --git a/packages/xrpl/src/Wallet/index.ts b/packages/xrpl/src/Wallet/index.ts index 161db6da9f..74a6fbb210 100644 --- a/packages/xrpl/src/Wallet/index.ts +++ b/packages/xrpl/src/Wallet/index.ts @@ -409,7 +409,7 @@ export class Wallet { * This will throw a more clear error for JS users if the supplied transaction has incorrect formatting */ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type - validate(tx as unknown as Record, Boolean(definitions)) + validate(tx as unknown as Record, definitions) const txToSignAndEncode = { ...tx } diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 5af72d038a..8189cf168b 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -1,5 +1,5 @@ import { isValidClassicAddress, isValidXAddress } from 'ripple-address-codec' -import { TRANSACTION_TYPES } from 'ripple-binary-codec' +import { TRANSACTION_TYPES, XrplDefinitionsBase } from 'ripple-binary-codec' import { ValidationError } from '../../errors' import { @@ -351,6 +351,24 @@ export function validateBaseTransaction(common: Record): void { validateOptionalField(common, 'NetworkID', isNumber) } +/** + * Validate that the passed transaction is a valid type against the types provided by the custom definitions. + * + * @param tx - A Transaction. + * @param definitions - Custom definitions + * @throws When the passed transaction type is not found in the definitions. + */ +export function validateTxAgainstCustomDefintions( + tx: Record, + definitions: XrplDefinitionsBase, +): void { + // Validate just transaction type for now, leaving it open for further validations against the custom definition spec. + const txType = tx.TransactionType + if (!definitions.transactionType[txType]) { + throw new ValidationError(`Invalid transaction type: ${txType}`) + } +} + /** * Parse the value of an amount, expressed either in XRP or as an Issued Currency, into a number. * diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index ccb110a38d..df1965b656 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -1,6 +1,8 @@ /* eslint-disable max-lines -- need to work with a lot of transactions in a switch statement */ /* eslint-disable max-lines-per-function -- need to work with a lot of Tx verifications */ +import { XrplDefinitionsBase } from 'ripple-binary-codec' + import { ValidationError } from '../../errors' import { IssuedCurrencyAmount, Memo } from '../common' import { isHex } from '../utils' @@ -18,7 +20,11 @@ import { CheckCancel, validateCheckCancel } from './checkCancel' import { CheckCash, validateCheckCash } from './checkCash' import { CheckCreate, validateCheckCreate } from './checkCreate' import { Clawback, validateClawback } from './clawback' -import { BaseTransaction, isIssuedCurrency } from './common' +import { + BaseTransaction, + isIssuedCurrency, + validateTxAgainstCustomDefintions, +} from './common' import { DepositPreauth, validateDepositPreauth } from './depositPreauth' import { DIDDelete, validateDIDDelete } from './DIDDelete' import { DIDSet, validateDIDSet } from './DIDSet' @@ -166,13 +172,13 @@ export interface TransactionAndMetadata< * Encode/decode and individual type validation. * * @param transaction - A Transaction. - * @param hasCustomDefinition - Whether the transaction has a custom definition. + * @param customDefinitions - Optional parameter to validate against a custom definition. * @throws ValidationError When the Transaction is malformed. * @category Utilities */ export function validate( transaction: Record, - hasCustomDefinition?: boolean, + customDefinitions?: XrplDefinitionsBase, ): void { const tx = { ...transaction } if (tx.TransactionType == null) { @@ -399,7 +405,9 @@ export function validate( break default: - if (!hasCustomDefinition) { + if (customDefinitions) { + validateTxAgainstCustomDefintions(tx, customDefinitions) + } else { throw new ValidationError( `Invalid field TransactionType: ${tx.TransactionType}`, ) diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index 165a057c67..f4c0e60fd1 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -1218,6 +1218,34 @@ describe('Wallet', function () { }) }) + it('sign fails when a custom definition is passed and the transaction type is not included in it', async function () { + const customDefinition = new XrplDefinitions( + rippled.definitions.customDefinition, + ) + const tx = { + Account: wallet.address, + TransactionType: 'SomeUnknown', + Flags: 2147483648, + Sequence: 33626, + Fee: '10', + AccountOther: 'rJyZ28c179hKg7Gwt4P2S8zgzUTmMUMmzs', + Expiration: 773819038, + Amount: { + currency: 'AAA', + issuer: 'rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT', + value: '1', + }, + AmountOther: { + currency: 'BBB', + issuer: 'rDCcTxoALtAryzk4TE3mxU9hpjRm5vQcxT', + value: '1', + }, + } + assert.throws(() => { + wallet.sign(tx as any, false, customDefinition) + }, /^Invalid transaction type: SomeUnknown$/u) + }) + it('multisign succeeds when a custom definition is passed', async function () { const customDefinition = new XrplDefinitions( rippled.definitions.customDefinition, From 2900ab38355a85e0feb1859c3fa30b0b3689e7b9 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Thu, 5 Sep 2024 11:25:36 -0400 Subject: [PATCH 12/15] Update packages/xrpl/src/client/index.ts Co-authored-by: tequ --- packages/xrpl/src/client/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/xrpl/src/client/index.ts b/packages/xrpl/src/client/index.ts index 88f54df409..76a5014652 100644 --- a/packages/xrpl/src/client/index.ts +++ b/packages/xrpl/src/client/index.ts @@ -225,6 +225,7 @@ class Client extends EventEmitter { */ public definitions: XrplDefinitionsBase | undefined + /** * API Version used by the server this client is connected to * */ From 2c60a1eccf86df388baceb5c76a74d67becb6f72 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Fri, 13 Sep 2024 13:02:45 +0100 Subject: [PATCH 13/15] fix: address lint errors --- packages/xrpl/src/models/transactions/common.ts | 8 +++++++- packages/xrpl/test/wallet/index.test.ts | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 8189cf168b..4b86d2717c 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -363,7 +363,13 @@ export function validateTxAgainstCustomDefintions( definitions: XrplDefinitionsBase, ): void { // Validate just transaction type for now, leaving it open for further validations against the custom definition spec. - const txType = tx.TransactionType + const txType = tx.TransactionType + if (typeof txType !== 'string') { + throw new ValidationError( + 'TransactionType field is not specified or not a string', + ) + } + if (!definitions.transactionType[txType]) { throw new ValidationError(`Invalid transaction type: ${txType}`) } diff --git a/packages/xrpl/test/wallet/index.test.ts b/packages/xrpl/test/wallet/index.test.ts index f4c0e60fd1..85a5219d29 100644 --- a/packages/xrpl/test/wallet/index.test.ts +++ b/packages/xrpl/test/wallet/index.test.ts @@ -1211,6 +1211,7 @@ describe('Wallet', function () { value: '1', }, } + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- for unknown transaction const result = wallet.sign(tx as any, false, customDefinition) assert.deepEqual(result, { tx_blob: RESPONSE_FIXTURES.signCustomDefinition.signedTransaction, @@ -1242,6 +1243,7 @@ describe('Wallet', function () { }, } assert.throws(() => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- for unknown transaction wallet.sign(tx as any, false, customDefinition) }, /^Invalid transaction type: SomeUnknown$/u) }) @@ -1251,6 +1253,7 @@ describe('Wallet', function () { rippled.definitions.customDefinition, ) const result = wallet.sign( + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- for unknown transaction REQUEST_FIXTURES.signAsCustomDefinition as any, true, customDefinition, From 071beb5f50502e5e056f0810eda7e099b617b1a0 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Thu, 21 Nov 2024 17:47:39 +0000 Subject: [PATCH 14/15] docs: update history on xrpl package --- packages/xrpl/HISTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index 7c3bcf9532..6e41fa6017 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -6,6 +6,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ### Added * parseTransactionFlags as a utility function in the xrpl package to streamline transactions flags-to-map conversion +* Adds support for Custom Definitions to `client.submit()` and `client.submitAndWait()` ## 4.0.0 (2024-07-15) From 04446ffe137783f8dba6b630fcf96a9fee44b208 Mon Sep 17 00:00:00 2001 From: Javi Romero Date: Thu, 21 Nov 2024 17:58:44 +0000 Subject: [PATCH 15/15] chore: typo validateTxAgainstCustomDefintions --- packages/xrpl/src/models/transactions/common.ts | 2 +- packages/xrpl/src/models/transactions/transaction.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xrpl/src/models/transactions/common.ts b/packages/xrpl/src/models/transactions/common.ts index 4b86d2717c..eb875a88c2 100644 --- a/packages/xrpl/src/models/transactions/common.ts +++ b/packages/xrpl/src/models/transactions/common.ts @@ -358,7 +358,7 @@ export function validateBaseTransaction(common: Record): void { * @param definitions - Custom definitions * @throws When the passed transaction type is not found in the definitions. */ -export function validateTxAgainstCustomDefintions( +export function validateTxAgainstCustomDefinitions( tx: Record, definitions: XrplDefinitionsBase, ): void { diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index 8decc2b6c7..72d73b1d6e 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -23,7 +23,7 @@ import { Clawback, validateClawback } from './clawback' import { BaseTransaction, isIssuedCurrency, - validateTxAgainstCustomDefintions, + validateTxAgainstCustomDefinitions, } from './common' import { DepositPreauth, validateDepositPreauth } from './depositPreauth' import { DIDDelete, validateDIDDelete } from './DIDDelete' @@ -418,7 +418,7 @@ export function validate( default: if (customDefinitions) { - validateTxAgainstCustomDefintions(tx, customDefinitions) + validateTxAgainstCustomDefinitions(tx, customDefinitions) } else { throw new ValidationError( `Invalid field TransactionType: ${tx.TransactionType}`,