diff --git a/.vscode/extenstions.json b/.vscode/extensions.json similarity index 100% rename from .vscode/extenstions.json rename to .vscode/extensions.json diff --git a/src/client/index.ts b/src/client/index.ts index 940f3cb0..dbc38c85 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -379,7 +379,7 @@ class Client extends EventEmitter { // NOTE: This may return much more than needed. Set limit when possible. const countTo: number = request.limit != null ? request.limit : Infinity; let count = 0; - let marker: string = request.marker; + let marker = request.marker; let lastBatchLength: number; const results: any[] = []; do { diff --git a/src/common/types/commands/account_lines.ts b/src/common/types/commands/account_lines.ts index d93c0972..42c7b40a 100644 --- a/src/common/types/commands/account_lines.ts +++ b/src/common/types/commands/account_lines.ts @@ -6,7 +6,7 @@ export interface AccountLinesRequest { ledger_index?: number | ("validated" | "closed" | "current"); peer?: string; limit?: number; - marker?: any; + marker?: unknown; } export interface AccountLinesResponse { @@ -15,5 +15,5 @@ export interface AccountLinesResponse { ledger_current_index?: number; ledger_index?: number; ledger_hash?: string; - marker?: any; + marker?: unknown; } diff --git a/src/common/types/commands/account_offers.ts b/src/common/types/commands/account_offers.ts index 50eee18a..a68af7d7 100644 --- a/src/common/types/commands/account_offers.ts +++ b/src/common/types/commands/account_offers.ts @@ -5,7 +5,7 @@ export interface AccountOffersRequest { ledger_hash?: string; ledger_index?: number | ("validated" | "closed" | "current"); limit?: number; - marker?: any; + marker?: unknown; } export interface AccountOffersResponse { @@ -13,7 +13,7 @@ export interface AccountOffersResponse { ledger_hash?: string; ledger_current_index?: number; ledger_index?: number; - marker?: any; + marker?: unknown; offers?: AccountOffer[]; } diff --git a/src/common/types/commands/book_offers.ts b/src/common/types/commands/book_offers.ts index a5017bc8..11b7b861 100644 --- a/src/common/types/commands/book_offers.ts +++ b/src/common/types/commands/book_offers.ts @@ -11,7 +11,7 @@ export interface BookOffersRequest { ledger_hash?: string; ledger_index?: number | ("validated" | "closed" | "current"); limit?: number; - marker?: any; + marker?: unknown; } export interface BookOffersResponse { @@ -19,7 +19,7 @@ export interface BookOffersResponse { ledger_hash?: string; ledger_current_index?: number; ledger_index?: number; - marker?: any; + marker?: unknown; } export interface BookOffer extends OfferLedgerEntry { diff --git a/src/models/common/index.ts b/src/models/common/index.ts index 9f4eb704..c9aeebb8 100644 --- a/src/models/common/index.ts +++ b/src/models/common/index.ts @@ -8,11 +8,11 @@ export type AccountObjectType = | "signer_list" | "state"; -export interface XRP { +interface XRP { currency: "XRP"; } -export interface IssuedCurrency { +interface IssuedCurrency { currency: string; issuer: string; } diff --git a/src/models/common/transaction.ts b/src/models/common/transaction.ts deleted file mode 100644 index 79a6e6ea..00000000 --- a/src/models/common/transaction.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Amount } from "."; - -interface CreatedNode { - CreatedNode: { - LedgerEntryType: string; - LedgerIndex: string; - NewFields: { [field: string]: any }; - }; -} - -interface ModifiedNode { - ModifiedNode: { - LedgerEntryType: string; - LedgerIndex: string; - FinalFields: { [field: string]: any }; - PreviousFields: { [field: string]: any }; - PreviousTxnID?: string; - PreviouTxnLgrSeq?: number; - }; -} - -interface DeletedNode { - DeletedNode: { - LedgerEntryType: string; - LedgerIndex: string; - FinalFields: { [field: string]: any }; - }; -} - -type Node = CreatedNode | ModifiedNode | DeletedNode; - -export interface TransactionMetadata { - AffectedNodes: Node[]; - DeliveredAmount?: Amount; - delivered_amount?: Amount; - TransactionIndex: number; - TransactionResult: string; -} diff --git a/src/models/ledger/accountRoot.ts b/src/models/ledger/accountRoot.ts index 7b5c2950..6e871d1e 100644 --- a/src/models/ledger/accountRoot.ts +++ b/src/models/ledger/accountRoot.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface AccountRoot extends BaseLedgerEntry { +export default interface AccountRoot extends BaseLedgerEntry { LedgerEntryType: "AccountRoot"; Account: string; Balance: string; diff --git a/src/models/ledger/amendments.ts b/src/models/ledger/amendments.ts index 3427b34d..c472ddbc 100644 --- a/src/models/ledger/amendments.ts +++ b/src/models/ledger/amendments.ts @@ -1,4 +1,4 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; interface Majority { Majority: { @@ -7,7 +7,7 @@ interface Majority { }; } -export interface Amendments extends BaseLedgerEntry { +export default interface Amendments extends BaseLedgerEntry { LedgerEntryType: "Amendments"; Amendments?: string[]; Majorities?: Majority[]; diff --git a/src/models/ledger/baseLedgerEntry.ts b/src/models/ledger/baseLedgerEntry.ts index ab70beb6..eda3b127 100644 --- a/src/models/ledger/baseLedgerEntry.ts +++ b/src/models/ledger/baseLedgerEntry.ts @@ -1,3 +1,3 @@ -export interface BaseLedgerEntry { +export default interface BaseLedgerEntry { index: string; } diff --git a/src/models/ledger/check.ts b/src/models/ledger/check.ts index b10f2756..83dd8d81 100644 --- a/src/models/ledger/check.ts +++ b/src/models/ledger/check.ts @@ -1,8 +1,8 @@ import { Amount } from "../common"; -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface Check extends BaseLedgerEntry { +export default interface Check extends BaseLedgerEntry { LedgerEntryType: "Check"; Account: string; Destination: string; diff --git a/src/models/ledger/depositPreauth.ts b/src/models/ledger/depositPreauth.ts index 0d48caf2..0ab82153 100644 --- a/src/models/ledger/depositPreauth.ts +++ b/src/models/ledger/depositPreauth.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface DepositPreauth extends BaseLedgerEntry { +export default interface DepositPreauth extends BaseLedgerEntry { LedgerEntryType: "DepositPreauth"; Account: string; Authorize: string; diff --git a/src/models/ledger/directoryNode.ts b/src/models/ledger/directoryNode.ts index f0e0b8ee..b60fab39 100644 --- a/src/models/ledger/directoryNode.ts +++ b/src/models/ledger/directoryNode.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface DirectoryNode extends BaseLedgerEntry { +export default interface DirectoryNode extends BaseLedgerEntry { LedgerEntryType: "DirectoryNode"; Flags: number; RootIndex: string; diff --git a/src/models/ledger/escrow.ts b/src/models/ledger/escrow.ts index 6ff0a299..950bdce4 100644 --- a/src/models/ledger/escrow.ts +++ b/src/models/ledger/escrow.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface Escrow extends BaseLedgerEntry { +export default interface Escrow extends BaseLedgerEntry { LedgerEntryType: "Escrow"; Account: string; Destination: string; diff --git a/src/models/ledger/feeSettings.ts b/src/models/ledger/feeSettings.ts index a29168b8..53550405 100644 --- a/src/models/ledger/feeSettings.ts +++ b/src/models/ledger/feeSettings.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface FeeSettings extends BaseLedgerEntry { +export default interface FeeSettings extends BaseLedgerEntry { LedgerEntryType: "FeeSettings"; BaseFee: string; ReferenceFeeUnits: number; diff --git a/src/models/ledger/index.ts b/src/models/ledger/index.ts index 340de5da..58ea1838 100644 --- a/src/models/ledger/index.ts +++ b/src/models/ledger/index.ts @@ -1,34 +1,21 @@ -import { AccountRoot } from "./accountRoot"; -import { Amendments } from "./amendments"; -import { Check } from "./check"; -import { DepositPreauth } from "./depositPreauth"; -import { DirectoryNode } from "./directoryNode"; -import { Escrow } from "./escrow"; -import { FeeSettings } from "./feeSettings"; -import { Ledger } from "./ledger"; -import { LedgerHashes } from "./ledgerHashes"; -import { NegativeUNL } from "./negativeUNL"; -import { Offer } from "./offer"; -import { PayChannel } from "./payChannel"; -import { RippleState } from "./rippleState"; -import { SignerList } from "./signerList"; -import { Ticket } from "./ticket"; - -export type LedgerEntry = - | AccountRoot - | Amendments - | Check - | DepositPreauth - | DirectoryNode - | Escrow - | FeeSettings - | LedgerHashes - | NegativeUNL - | Offer - | PayChannel - | RippleState - | SignerList - | Ticket; +/* eslint-disable import/max-dependencies -- Needs to export all ledger objects */ +/* eslint-disable import/no-unused-modules -- Needs to export all ledger objects */ +import AccountRoot from "./accountRoot"; +import Amendments from "./amendments"; +import Check from "./check"; +import DepositPreauth from "./depositPreauth"; +import DirectoryNode from "./directoryNode"; +import Escrow from "./escrow"; +import FeeSettings from "./feeSettings"; +import Ledger from "./ledger"; +import LedgerEntry from "./ledgerEntry"; +import LedgerHashes from "./ledgerHashes"; +import NegativeUNL from "./negativeUNL"; +import Offer from "./offer"; +import PayChannel from "./payChannel"; +import RippleState from "./rippleState"; +import SignerList from "./signerList"; +import Ticket from "./ticket"; export { AccountRoot, @@ -38,6 +25,8 @@ export { DirectoryNode, Escrow, FeeSettings, + Ledger, + LedgerEntry, LedgerHashes, NegativeUNL, Offer, @@ -45,5 +34,4 @@ export { RippleState, SignerList, Ticket, - Ledger, }; diff --git a/src/models/ledger/ledger.ts b/src/models/ledger/ledger.ts index ea9e8106..ecd3fdda 100644 --- a/src/models/ledger/ledger.ts +++ b/src/models/ledger/ledger.ts @@ -1,8 +1,8 @@ import { Transaction } from "../transactions"; -import { LedgerEntry } from "."; +import LedgerEntry from "./ledgerEntry"; -export interface Ledger { +export default interface Ledger { account_hash: string; accountState?: LedgerEntry[]; close_flags: number; diff --git a/src/models/ledger/ledgerEntry.ts b/src/models/ledger/ledgerEntry.ts new file mode 100644 index 00000000..d5f513dc --- /dev/null +++ b/src/models/ledger/ledgerEntry.ts @@ -0,0 +1,33 @@ +/* eslint-disable import/max-dependencies -- Needed for the type */ +import AccountRoot from "./accountRoot"; +import Amendments from "./amendments"; +import Check from "./check"; +import DepositPreauth from "./depositPreauth"; +import DirectoryNode from "./directoryNode"; +import Escrow from "./escrow"; +import FeeSettings from "./feeSettings"; +import LedgerHashes from "./ledgerHashes"; +import NegativeUNL from "./negativeUNL"; +import Offer from "./offer"; +import PayChannel from "./payChannel"; +import RippleState from "./rippleState"; +import SignerList from "./signerList"; +import Ticket from "./ticket"; + +type LedgerEntry = + | AccountRoot + | Amendments + | Check + | DepositPreauth + | DirectoryNode + | Escrow + | FeeSettings + | LedgerHashes + | NegativeUNL + | Offer + | PayChannel + | RippleState + | SignerList + | Ticket; + +export default LedgerEntry; diff --git a/src/models/ledger/ledgerHashes.ts b/src/models/ledger/ledgerHashes.ts index 999d574e..cb140f3a 100644 --- a/src/models/ledger/ledgerHashes.ts +++ b/src/models/ledger/ledgerHashes.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface LedgerHashes extends BaseLedgerEntry { +export default interface LedgerHashes extends BaseLedgerEntry { LedgerEntryType: "LedgerHashes"; LastLedgerSequence?: number; Hashes: string[]; diff --git a/src/models/ledger/negativeUNL.ts b/src/models/ledger/negativeUNL.ts index 82dd61f8..f12c25eb 100644 --- a/src/models/ledger/negativeUNL.ts +++ b/src/models/ledger/negativeUNL.ts @@ -1,11 +1,11 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; interface DisabledValidator { FirstLedgerSequence: number; PublicKey: string; } -export interface NegativeUNL extends BaseLedgerEntry { +export default interface NegativeUNL extends BaseLedgerEntry { LedgerEntryType: "NegativeUNL"; DisabledValidators?: DisabledValidator[]; ValidatorToDisable?: string; diff --git a/src/models/ledger/offer.ts b/src/models/ledger/offer.ts index 7684cbcb..387a91a7 100644 --- a/src/models/ledger/offer.ts +++ b/src/models/ledger/offer.ts @@ -1,8 +1,8 @@ import { Amount } from "../common"; -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface Offer extends BaseLedgerEntry { +export default interface Offer extends BaseLedgerEntry { LedgerEntryType: "Offer"; Flags: number; Account: string; diff --git a/src/models/ledger/payChannel.ts b/src/models/ledger/payChannel.ts index 8ec31f59..1e5972ed 100644 --- a/src/models/ledger/payChannel.ts +++ b/src/models/ledger/payChannel.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface PayChannel extends BaseLedgerEntry { +export default interface PayChannel extends BaseLedgerEntry { LedgerEntryType: "PayChannel"; Account: string; Destination: string; diff --git a/src/models/ledger/rippleState.ts b/src/models/ledger/rippleState.ts index 6a839a06..115f331f 100644 --- a/src/models/ledger/rippleState.ts +++ b/src/models/ledger/rippleState.ts @@ -1,8 +1,8 @@ import { IssuedCurrencyAmount } from "../common"; -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface RippleState extends BaseLedgerEntry { +export default interface RippleState extends BaseLedgerEntry { LedgerEntryType: "RippleState"; Flags: number; Balance: IssuedCurrencyAmount; diff --git a/src/models/ledger/signerList.ts b/src/models/ledger/signerList.ts index bdd68561..800eb529 100644 --- a/src/models/ledger/signerList.ts +++ b/src/models/ledger/signerList.ts @@ -1,4 +1,4 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; interface SignerEntry { SignerEntry: { @@ -7,7 +7,7 @@ interface SignerEntry { }; } -export interface SignerList extends BaseLedgerEntry { +export default interface SignerList extends BaseLedgerEntry { LedgerEntryType: "SignerList"; Flags: number; PreviousTxnID: string; diff --git a/src/models/ledger/ticket.ts b/src/models/ledger/ticket.ts index b6050753..636c4a2d 100644 --- a/src/models/ledger/ticket.ts +++ b/src/models/ledger/ticket.ts @@ -1,6 +1,6 @@ -import { BaseLedgerEntry } from "./baseLedgerEntry"; +import BaseLedgerEntry from "./baseLedgerEntry"; -export interface Ticket extends BaseLedgerEntry { +export default interface Ticket extends BaseLedgerEntry { LedgerEntryType: "Ticket"; Account: string; Flags: number; diff --git a/src/models/methods/accountChannels.ts b/src/models/methods/accountChannels.ts index b6efc276..01e06e50 100644 --- a/src/models/methods/accountChannels.ts +++ b/src/models/methods/accountChannels.ts @@ -24,7 +24,7 @@ export interface AccountChannelsRequest extends BaseRequest { ledger_hash?: string; ledger_index?: LedgerIndex; limit: number; - marker?: any; + marker?: unknown; } export interface AccountChannelsResponse extends BaseResponse { @@ -35,6 +35,6 @@ export interface AccountChannelsResponse extends BaseResponse { ledger_index: number; validated?: boolean; limit?: number; - marker?: any; + marker?: unknown; }; } diff --git a/src/models/methods/accountLines.ts b/src/models/methods/accountLines.ts index f5144c0c..eef7aeca 100644 --- a/src/models/methods/accountLines.ts +++ b/src/models/methods/accountLines.ts @@ -25,7 +25,7 @@ export interface AccountLinesRequest extends BaseRequest { ledger_index?: LedgerIndex; peer?: string; limit?: number; - marker?: any; + marker?: unknown; } export interface AccountLinesResponse extends BaseResponse { @@ -35,6 +35,6 @@ export interface AccountLinesResponse extends BaseResponse { ledger_current_index?: number; ledger_index?: number; ledger_hash?: string; - marker?: any; + marker?: unknown; }; } diff --git a/src/models/methods/accountObjects.ts b/src/models/methods/accountObjects.ts index 29509242..9671cba2 100644 --- a/src/models/methods/accountObjects.ts +++ b/src/models/methods/accountObjects.ts @@ -20,7 +20,7 @@ export interface AccountObjectsRequest extends BaseRequest { ledger_hash?: string; ledger_index?: LedgerIndex; limit?: number; - marker?: any; + marker?: unknown; } type AccountObject = diff --git a/src/models/methods/accountOffers.ts b/src/models/methods/accountOffers.ts index 5516eeba..ec1dc030 100644 --- a/src/models/methods/accountOffers.ts +++ b/src/models/methods/accountOffers.ts @@ -8,7 +8,7 @@ export interface AccountOffersRequest extends BaseRequest { ledger_hash?: string; ledger_index?: LedgerIndex; limit?: number; - marker?: any; + marker?: unknown; strict?: boolean; } @@ -28,6 +28,6 @@ export interface AccountOffersResponse extends BaseResponse { ledger_current_index?: number; ledger_index?: number; ledger_hash?: string; - marker?: any; + marker?: unknown; }; } diff --git a/src/models/methods/accountTx.ts b/src/models/methods/accountTx.ts index e0abb1d5..03842b96 100644 --- a/src/models/methods/accountTx.ts +++ b/src/models/methods/accountTx.ts @@ -1,5 +1,6 @@ import { LedgerIndex } from "../common"; -import Metadata from "../common/metadata"; +import { Transaction } from "../transactions"; +import Metadata from "../transactions/metadata"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -13,13 +14,13 @@ export interface AccountTxRequest extends BaseRequest { binary?: boolean; forward?: boolean; limit?: number; - marker?: any; + marker?: unknown; } interface AccountTransaction { ledger_index: number; meta: string | Metadata; - tx?: any; // TODO: replace when transaction objects are done + tx?: Transaction; tx_blob?: string; validated: boolean; } @@ -30,7 +31,7 @@ export interface AccountTxResponse extends BaseResponse { ledger_index_min: number; ledger_index_max: number; limit: number; - marker?: any; + marker?: unknown; transactions: AccountTransaction[]; validated?: boolean; }; diff --git a/src/models/methods/baseMethod.ts b/src/models/methods/baseMethod.ts index 0d1af5c0..f7ce06d9 100644 --- a/src/models/methods/baseMethod.ts +++ b/src/models/methods/baseMethod.ts @@ -1,5 +1,3 @@ -import { Response } from "."; - export interface BaseRequest { id?: number | string; command: string; @@ -16,12 +14,13 @@ export interface BaseResponse { id: number | string; status: "success" | "error" | string; type: "response" | string; - result: any; + result: unknown; warning?: "load"; warnings?: Warning[]; forwarded?: boolean; error?: string; error_message?: string; - request?: Response; + // TODO: type this better + request?: unknown; api_version?: number; } diff --git a/src/models/methods/index.ts b/src/models/methods/index.ts index 4a8897be..be684cf0 100644 --- a/src/models/methods/index.ts +++ b/src/models/methods/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable import/max-dependencies -- All methods need to be exported */ + import { AccountChannelsRequest, AccountChannelsResponse, @@ -64,7 +66,8 @@ import { import { TxRequest, TxResponse } from "./tx"; import { UnsubscribeRequest, UnsubscribeResponse } from "./unsubscribe"; -type Request = // account methods +// account methods +type Request = | AccountChannelsRequest | AccountCurrenciesRequest | AccountInfoRequest @@ -104,7 +107,8 @@ type Request = // account methods | PingRequest | RandomRequest; -type Response = // account methods +// account methods +type Response = | AccountChannelsResponse | AccountCurrenciesResponse | AccountInfoResponse diff --git a/src/models/methods/ledger.ts b/src/models/methods/ledger.ts index 59c7ebd2..8d5ac421 100644 --- a/src/models/methods/ledger.ts +++ b/src/models/methods/ledger.ts @@ -1,5 +1,7 @@ import { LedgerIndex } from "../common"; import { Ledger } from "../ledger"; +import { Transaction, TransactionAndMetadata } from "../transactions"; +import TransactionMetadata from "../transactions/metadata"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -16,12 +18,21 @@ export interface LedgerRequest extends BaseRequest { queue?: boolean; } +interface ModifiedMetadata extends TransactionMetadata { + owner_funds: string; +} + +interface ModifiedOfferCreateTransaction { + transaction: Transaction; + metadata: ModifiedMetadata; +} + interface LedgerQueueData { account: string; - // TODO: Retype tx once we have transaction types - // Also include tx_blob as possible type: https://xrpl.org/ledger.html - // Also handle the special case where 'owner_funds: string' is a field of OfferCreate sometimes - https://xrpl.org/ledger.html#response-format - tx: any; + tx: + | TransactionAndMetadata + | ModifiedOfferCreateTransaction + | { tx_blob: string }; retries_remaining: number; preflight_result: string; last_result?: string; @@ -43,6 +54,6 @@ export interface LedgerResponse extends BaseResponse { ledger_hash: string; ledger_index: number; queue_data?: Array; - validated: boolean; // TODO: Figure out if the example is correct, or the documentation for this field - https://xrpl.org/ledger.html#response-format + validated?: boolean; }; } diff --git a/src/models/methods/ledgerData.ts b/src/models/methods/ledgerData.ts index 88bd98c0..286d6a2e 100644 --- a/src/models/methods/ledgerData.ts +++ b/src/models/methods/ledgerData.ts @@ -9,7 +9,7 @@ export interface LedgerDataRequest extends BaseRequest { ledger_index?: LedgerIndex; binary?: boolean; limit?: number; - marker?: any; + marker?: unknown; } type LabeledLedgerEntry = { ledgerEntryType: string } & LedgerEntry; @@ -25,6 +25,6 @@ export interface LedgerDataResponse extends BaseResponse { ledger_index: number; ledger_hash: string; state: State[]; - marker?: any; + marker?: unknown; }; } diff --git a/src/models/methods/norippleCheck.ts b/src/models/methods/norippleCheck.ts index 62628fb8..31b76207 100644 --- a/src/models/methods/norippleCheck.ts +++ b/src/models/methods/norippleCheck.ts @@ -1,4 +1,5 @@ import { LedgerIndex } from "../common"; +import { Transaction } from "../transactions"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -15,6 +16,6 @@ export interface NoRippleCheckResponse extends BaseResponse { result: { ledger_current_index: number; problems: string[]; - transactions: any[]; // TODO: fix once transaction objects are implemented + transactions: Transaction[]; }; } diff --git a/src/models/methods/pathFind.ts b/src/models/methods/pathFind.ts index 2d65858a..c8f7ec3a 100644 --- a/src/models/methods/pathFind.ts +++ b/src/models/methods/pathFind.ts @@ -7,7 +7,7 @@ interface BasePathFindRequest extends BaseRequest { subcommand: string; } -export interface PathFindCreateRequest extends BasePathFindRequest { +interface PathFindCreateRequest extends BasePathFindRequest { subcommand: "create"; source_account: string; destination_account: string; diff --git a/src/models/methods/ping.ts b/src/models/methods/ping.ts index 113c7eb6..42eb00b7 100644 --- a/src/models/methods/ping.ts +++ b/src/models/methods/ping.ts @@ -5,5 +5,7 @@ export interface PingRequest extends BaseRequest { } export interface PingResponse extends BaseResponse { + // TODO: figure out if there's a better way to type this + // eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object result: {}; } diff --git a/src/models/methods/submit.ts b/src/models/methods/submit.ts index 95ef6a5a..6ba465e1 100644 --- a/src/models/methods/submit.ts +++ b/src/models/methods/submit.ts @@ -1,3 +1,5 @@ +import { Transaction } from "../transactions"; + import { BaseRequest, BaseResponse } from "./baseMethod"; export interface SubmitRequest extends BaseRequest { @@ -12,7 +14,7 @@ export interface SubmitResponse extends BaseResponse { engine_result_code: number; engine_result_message: string; tx_blob: string; - tx_json: any; // TODO: type this properly when we have Transaction types + tx_json: Transaction; accepted: boolean; account_sequence_available: number; account_sequence_next: number; diff --git a/src/models/methods/submitMultisigned.ts b/src/models/methods/submitMultisigned.ts index 4a147f4d..7b5e4f3f 100644 --- a/src/models/methods/submitMultisigned.ts +++ b/src/models/methods/submitMultisigned.ts @@ -1,8 +1,10 @@ +import { Transaction } from "../transactions"; + import { BaseRequest, BaseResponse } from "./baseMethod"; export interface SubmitMultisignedRequest extends BaseRequest { command: "submit_multisigned"; - tx_json: any; // TODO: type this properly when we have Transaction types + tx_json: Transaction; fail_hard?: boolean; } @@ -12,6 +14,6 @@ export interface SubmitMultisignedResponse extends BaseResponse { engine_result_code: number; engine_result_message: string; tx_blob: string; - tx_json: any; // TODO: type this properly when we have Transaction types + tx_json: Transaction; }; } diff --git a/src/models/methods/subscribe.ts b/src/models/methods/subscribe.ts index c598e852..81f8fa65 100644 --- a/src/models/methods/subscribe.ts +++ b/src/models/methods/subscribe.ts @@ -1,5 +1,7 @@ +import { OfferCreateTransaction } from "../../common/types/objects"; import { Currency, StreamType } from "../common"; -import { TransactionMetadata } from "../common/transaction"; +import { Transaction } from "../transactions"; +import TransactionMetadata from "../transactions/metadata"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -23,7 +25,9 @@ export interface SubscribeRequest extends BaseRequest { } export interface SubscribeResponse extends BaseResponse { - result: any; + // TODO: figure out if there's a better way to type this + // eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object + result: {} | Stream; } interface BaseStream { @@ -70,7 +74,7 @@ export interface TransactionStream extends BaseStream { ledger_hash?: string; ledger_index?: number; meta?: TransactionMetadata; - transaction: any; // TODO: replace when we have types for transactions + transaction: Transaction; validated?: boolean; } @@ -88,6 +92,10 @@ export interface PeerStatusStream extends BaseStream { ledger_index_min?: number; } +interface ModifiedOfferCreateTransaction extends OfferCreateTransaction { + owner_funds: string; +} + export interface OrderBookStream extends BaseStream { status: string; type: "transaction"; @@ -98,9 +106,7 @@ export interface OrderBookStream extends BaseStream { ledger_hash?: string; ledger_index?: number; meta: TransactionMetadata; - transaction: any; // TODO: replace when we have types for transactions - // TODO: transactions for this object have a special case for OfferCreate - // https://xrpl.org/subscribe.html#order-book-streams + transaction: Transaction | ModifiedOfferCreateTransaction; validated: boolean; } diff --git a/src/models/methods/transactionEntry.ts b/src/models/methods/transactionEntry.ts index 3dd82ea6..ec74ae7f 100644 --- a/src/models/methods/transactionEntry.ts +++ b/src/models/methods/transactionEntry.ts @@ -1,5 +1,6 @@ import { LedgerIndex } from "../common"; -import { TransactionMetadata } from "../common/transaction"; +import { Transaction } from "../transactions"; +import TransactionMetadata from "../transactions/metadata"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -15,6 +16,6 @@ export interface TransactionEntryResponse extends BaseResponse { ledger_hash: string; ledger_index: number; metadata: TransactionMetadata; - tx_json: any; // TODO: type this properly when we have Transaction types + tx_json: Transaction; }; } diff --git a/src/models/methods/tx.ts b/src/models/methods/tx.ts index 78c1d843..03a61640 100644 --- a/src/models/methods/tx.ts +++ b/src/models/methods/tx.ts @@ -1,4 +1,5 @@ -import { TransactionMetadata } from "../common/transaction"; +import { Transaction } from "../transactions"; +import TransactionMetadata from "../transactions/metadata"; import { BaseRequest, BaseResponse } from "./baseMethod"; @@ -16,6 +17,6 @@ export interface TxResponse extends BaseResponse { ledger_index: number; meta: TransactionMetadata | string; validated?: boolean; - }; // TODO: needs to be `& Transaction` once that type is available + } & Transaction; searched_all?: boolean; } diff --git a/src/models/methods/unsubscribe.ts b/src/models/methods/unsubscribe.ts index d9e67044..4c77cad2 100644 --- a/src/models/methods/unsubscribe.ts +++ b/src/models/methods/unsubscribe.ts @@ -17,5 +17,7 @@ export interface UnsubscribeRequest extends BaseRequest { } export interface UnsubscribeResponse extends BaseResponse { + // TODO: figure out if there's a better way to type this + // eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object result: {}; } diff --git a/src/models/transactions/accountDelete.ts b/src/models/transactions/accountDelete.ts index e3f465e6..97ec4f49 100644 --- a/src/models/transactions/accountDelete.ts +++ b/src/models/transactions/accountDelete.ts @@ -12,10 +12,9 @@ export interface AccountDelete extends BaseTransaction { * Verify the form and type of an AccountDelete at runtime. * * @param tx - An AccountDelete Transaction. - * @returns Void. * @throws When the AccountDelete is Malformed. */ -export function verifyAccountDelete(tx: AccountDelete): void { +export function verifyAccountDelete(tx: Record): void { verifyBaseTransaction(tx); if (tx.Destination === undefined) { diff --git a/src/models/transactions/accountSet.ts b/src/models/transactions/accountSet.ts index c72a36cc..1d77865f 100644 --- a/src/models/transactions/accountSet.ts +++ b/src/models/transactions/accountSet.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyAccountSet */ import { ValidationError } from "../../common/errors"; import { BaseTransaction, verifyBaseTransaction } from "./common"; @@ -25,14 +26,16 @@ export interface AccountSet extends BaseTransaction { TickSize?: number; } +const MIN_TICK_SIZE = 3; +const MAX_TICK_SIZE = 15; + /** * Verify the form and type of an AccountSet at runtime. * * @param tx - An AccountSet Transaction. - * @returns Void. * @throws When the AccountSet is Malformed. */ -export function verifyAccountSet(tx: AccountSet): void { +export function verifyAccountSet(tx: Record): void { verifyBaseTransaction(tx); if (tx.ClearFlag !== undefined) { @@ -73,7 +76,10 @@ export function verifyAccountSet(tx: AccountSet): void { if (typeof tx.TickSize !== "number") { throw new ValidationError("AccountSet: invalid TickSize"); } - if (tx.TickSize !== 0 && (tx.TickSize < 3 || tx.TickSize > 15)) { + if ( + tx.TickSize !== 0 && + (tx.TickSize < MIN_TICK_SIZE || tx.TickSize > MAX_TICK_SIZE) + ) { throw new ValidationError("AccountSet: invalid TickSize"); } } diff --git a/src/models/transactions/checkCancel.ts b/src/models/transactions/checkCancel.ts index af365142..cd851ef1 100644 --- a/src/models/transactions/checkCancel.ts +++ b/src/models/transactions/checkCancel.ts @@ -11,10 +11,9 @@ export interface CheckCancel extends BaseTransaction { * Verify the form and type of an CheckCancel at runtime. * * @param tx - An CheckCancel Transaction. - * @returns Void. * @throws When the CheckCancel is Malformed. */ -export function verifyCheckCancel(tx: CheckCancel): void { +export function verifyCheckCancel(tx: Record): void { verifyBaseTransaction(tx); if (tx.CheckID !== undefined && typeof tx.CheckID !== "string") { diff --git a/src/models/transactions/checkCash.ts b/src/models/transactions/checkCash.ts index 48044f64..cb32bc33 100644 --- a/src/models/transactions/checkCash.ts +++ b/src/models/transactions/checkCash.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyCheckCash */ import { ValidationError } from "../../common/errors"; import { Amount } from "../common"; @@ -14,34 +15,29 @@ export interface CheckCash extends BaseTransaction { * Verify the form and type of an CheckCash at runtime. * * @param tx - An CheckCash Transaction. - * @returns Void. * @throws When the CheckCash is Malformed. */ -export function verifyCheckCash(tx: CheckCash): void { +export function verifyCheckCash(tx: Record): void { verifyBaseTransaction(tx); - if (!tx.hasOwnProperty("Amount") && !tx.hasOwnProperty("DeliverMin")) { + if (tx.Amount == null && tx.DeliverMin == null) { throw new ValidationError( "CheckCash: must have either Amount or DeliverMin" ); } - if (tx.hasOwnProperty("Amount") && tx.hasOwnProperty("DeliverMin")) { + if (tx.Amount != null && tx.DeliverMin != null) { throw new ValidationError( "CheckCash: cannot have both Amount and DeliverMin" ); } - if ( - tx.hasOwnProperty("Amount") && - tx.Amount !== undefined && - !isAmount(tx.Amount) - ) { + if (tx.Amount != null && tx.Amount !== undefined && !isAmount(tx.Amount)) { throw new ValidationError("CheckCash: invalid Amount"); } if ( - tx.hasOwnProperty("DeliverMin") && + tx.DeliverMin != null && tx.DeliverMin !== undefined && !isAmount(tx.DeliverMin) ) { diff --git a/src/models/transactions/checkCreate.ts b/src/models/transactions/checkCreate.ts index 5dfc6947..c2639003 100644 --- a/src/models/transactions/checkCreate.ts +++ b/src/models/transactions/checkCreate.ts @@ -1,7 +1,12 @@ +/* eslint-disable complexity -- Necessary for verifyCheckCreate */ import { ValidationError } from "../../common/errors"; -import { Amount, IssuedCurrencyAmount } from "../common"; +import { Amount } from "../common"; -import { BaseTransaction, verifyBaseTransaction } from "./common"; +import { + BaseTransaction, + verifyBaseTransaction, + isIssuedCurrency, +} from "./common"; export interface CheckCreate extends BaseTransaction { TransactionType: "CheckCreate"; @@ -16,10 +21,9 @@ export interface CheckCreate extends BaseTransaction { * Verify the form and type of an CheckCreate at runtime. * * @param tx - An CheckCreate Transaction. - * @returns Void. * @throws When the CheckCreate is Malformed. */ -export function verifyCheckCreate(tx: CheckCreate): void { +export function verifyCheckCreate(tx: Record): void { verifyBaseTransaction(tx); if (tx.SendMax === undefined) { @@ -30,16 +34,11 @@ export function verifyCheckCreate(tx: CheckCreate): void { throw new ValidationError("CheckCreate: missing field Destination"); } - const isIssuedCurrency = (obj: IssuedCurrencyAmount): boolean => { - return ( - Object.keys(obj).length === 3 && - typeof obj.value === "string" && - typeof obj.issuer === "string" && - typeof obj.currency === "string" - ); - }; - - if (typeof tx.SendMax !== "string" && !isIssuedCurrency(tx.SendMax)) { + if ( + typeof tx.SendMax !== "string" && + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + !isIssuedCurrency(tx.SendMax as Record) + ) { throw new ValidationError("CheckCreate: invalid SendMax"); } diff --git a/src/models/transactions/common.ts b/src/models/transactions/common.ts index 1763a1d7..8db8cc76 100644 --- a/src/models/transactions/common.ts +++ b/src/models/transactions/common.ts @@ -1,5 +1,8 @@ +/* eslint-disable max-lines-per-function -- Necessary for verifyBaseTransaction */ +/* eslint-disable complexity -- Necessary for verifyBaseTransaction */ +/* eslint-disable max-statements -- Necessary for verifyBaseTransaction */ import { ValidationError } from "../../common/errors"; -import { Amount, Memo, Signer, IssuedCurrencyAmount } from "../common"; +import { Memo, Signer } from "../common"; import { onlyHasFields } from "../utils"; const transactionTypes = [ @@ -24,46 +27,72 @@ const transactionTypes = [ "TrustSet", ]; -const isMemo = (obj: { Memo: Memo }): boolean => { - const memo = obj.Memo; +const MEMO_SIZE = 3; + +function isMemo(obj: { Memo?: unknown }): boolean { + if (obj.Memo == null) { + return false; + } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + const memo = obj.Memo as Record; const size = Object.keys(memo).length; - const validData = - memo.MemoData === undefined || typeof memo.MemoData === "string"; + const validData = memo.MemoData == null || typeof memo.MemoData === "string"; const validFormat = - memo.MemoFormat === undefined || typeof memo.MemoData === "string"; - const validType = - memo.MemoType === undefined || typeof memo.MemoType === "string"; + memo.MemoFormat == null || typeof memo.MemoFormat === "string"; + const validType = memo.MemoType == null || typeof memo.MemoType === "string"; return ( size >= 1 && - size <= 3 && + size <= MEMO_SIZE && validData && validFormat && validType && onlyHasFields(memo, ["MemoFormat", "MemoData", "MemoType"]) ); -}; +} -const isSigner = (signer: Signer): boolean => { +const SIGNER_SIZE = 3; + +function isSigner(obj: unknown): boolean { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + const signer = obj as Record; return ( - Object.keys(signer).length === 3 && + Object.keys(signer).length === SIGNER_SIZE && typeof signer.Account === "string" && typeof signer.TxnSignature === "string" && typeof signer.SigningPubKey === "string" ); -}; +} -export function isIssuedCurrency(obj: IssuedCurrencyAmount): boolean { +const ISSUED_CURRENCY_SIZE = 3; + +/** + * Verify the form and type of an IssuedCurrencyAmount at runtime. + * + * @param obj - The object to check the form and type of. + * @returns Whether the IssuedCurrencyAmount is malformed. + */ +export function isIssuedCurrency(obj: Record): boolean { return ( - Object.keys(obj).length === 3 && + Object.keys(obj).length === ISSUED_CURRENCY_SIZE && typeof obj.value === "string" && typeof obj.issuer === "string" && typeof obj.currency === "string" ); } -export function isAmount(amount: Amount): boolean { - return typeof amount === "string" || isIssuedCurrency(amount); +/** + * Verify the form and type of an Amount at runtime. + * + * @param amount - The object to check the form and type of. + * @returns Whether the Amount is malformed. + */ +export function isAmount(amount: unknown): boolean { + return ( + typeof amount === "string" || + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + isIssuedCurrency(amount as Record) + ); } export interface GlobalFlags { @@ -92,10 +121,9 @@ export interface BaseTransaction { * any time a transaction will be verified. * * @param common - An interface w/ common transaction fields. - * @returns Void. * @throws When the common param is malformed. */ -export function verifyBaseTransaction(common: BaseTransaction): void { +export function verifyBaseTransaction(common: Record): void { if (common.Account === undefined) { throw new ValidationError("BaseTransaction: missing field Account"); } @@ -138,16 +166,18 @@ export function verifyBaseTransaction(common: BaseTransaction): void { throw new ValidationError("BaseTransaction: invalid LastLedgerSequence"); } - if ( - common.Memos !== undefined && - (common.Memos.length === 0 || !common.Memos.every(isMemo)) - ) { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + const memos = common.Memos as Array<{ Memo?: unknown }> | undefined; + if (memos !== undefined && !memos.every(isMemo)) { throw new ValidationError("BaseTransaction: invalid Memos"); } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + const signers = common.Signers as Array> | undefined; + if ( - common.Signers !== undefined && - (common.Signers.length === 0 || !common.Signers.every(isSigner)) + signers !== undefined && + (signers.length === 0 || !signers.every(isSigner)) ) { throw new ValidationError("BaseTransaction: invalid Signers"); } diff --git a/src/models/transactions/depositPreauth.ts b/src/models/transactions/depositPreauth.ts index 73379c11..427191f1 100644 --- a/src/models/transactions/depositPreauth.ts +++ b/src/models/transactions/depositPreauth.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyDepositPreauth */ import { ValidationError } from "../../common/errors"; import { BaseTransaction, verifyBaseTransaction } from "./common"; @@ -9,12 +10,12 @@ export interface DepositPreauth extends BaseTransaction { } /** + * Verify the form and type of a DepositPreauth at runtime. * * @param tx - A DepositPreauth Transaction. - * @returns - * @throws {ValidationError} When the DepositPreauth is malformed. + * @throws When the DepositPreauth is malformed. */ -export function verifyDepositPreauth(tx: DepositPreauth): void { +export function verifyDepositPreauth(tx: Record): void { verifyBaseTransaction(tx); if (tx.Authorize !== undefined && tx.Unauthorize !== undefined) { diff --git a/src/models/transactions/escrowCancel.ts b/src/models/transactions/escrowCancel.ts index 87dfcfed..5c7c4638 100644 --- a/src/models/transactions/escrowCancel.ts +++ b/src/models/transactions/escrowCancel.ts @@ -12,10 +12,9 @@ export interface EscrowCancel extends BaseTransaction { * Verify the form and type of an EscrowCancel at runtime. * * @param tx - An EscrowCancel Transaction. - * @returns Void. * @throws When the EscrowCancel is Malformed. */ -export function verifyEscrowCancel(tx: EscrowCancel): void { +export function verifyEscrowCancel(tx: Record): void { verifyBaseTransaction(tx); if (tx.Owner === undefined) { diff --git a/src/models/transactions/escrowCreate.ts b/src/models/transactions/escrowCreate.ts index bdc7acbd..06a3c714 100644 --- a/src/models/transactions/escrowCreate.ts +++ b/src/models/transactions/escrowCreate.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyEscrowCreate */ import { ValidationError } from "../../common/errors"; import { BaseTransaction, verifyBaseTransaction } from "./common"; @@ -16,10 +17,9 @@ export interface EscrowCreate extends BaseTransaction { * Verify the form and type of an EscrowCreate at runtime. * * @param tx - An EscrowCreate Transaction. - * @returns Void. * @throws When the EscrowCreate is Malformed. */ -export function verifyEscrowCreate(tx: EscrowCreate): void { +export function verifyEscrowCreate(tx: Record): void { verifyBaseTransaction(tx); if (tx.Amount === undefined) { diff --git a/src/models/transactions/escrowFinish.ts b/src/models/transactions/escrowFinish.ts index 72f339df..8f46612f 100644 --- a/src/models/transactions/escrowFinish.ts +++ b/src/models/transactions/escrowFinish.ts @@ -14,10 +14,9 @@ export interface EscrowFinish extends BaseTransaction { * Verify the form and type of an EscrowFinish at runtime. * * @param tx - An EscrowFinish Transaction. - * @returns Void. * @throws When the EscrowFinish is Malformed. */ -export function verifyEscrowFinish(tx: EscrowFinish): void { +export function verifyEscrowFinish(tx: Record): void { verifyBaseTransaction(tx); if (tx.Owner === undefined) { diff --git a/src/models/transactions/index.ts b/src/models/transactions/index.ts index a87c32e8..c784c188 100644 --- a/src/models/transactions/index.ts +++ b/src/models/transactions/index.ts @@ -1,3 +1,6 @@ +/* eslint-disable import/no-unused-modules -- Needs to export all types + verify methods */ +/* eslint-disable import/max-dependencies -- Needs to export all types + verify methods */ +// TODO: replace * imports with direct imports export * from "./transaction"; export * from "./accountSet"; export * from "./accountDelete"; @@ -10,7 +13,7 @@ export * from "./escrowCreate"; export * from "./escrowFinish"; export * from "./offerCancel"; export * from "./offerCreate"; -export * from "./paymentTransaction"; +export * from "./payment"; export * from "./paymentChannelClaim"; export * from "./paymentChannelCreate"; export * from "./paymentChannelFund"; diff --git a/src/models/common/metadata.ts b/src/models/transactions/metadata.ts similarity index 67% rename from src/models/common/metadata.ts rename to src/models/transactions/metadata.ts index 10b79e25..dc78b4ca 100644 --- a/src/models/common/metadata.ts +++ b/src/models/transactions/metadata.ts @@ -1,10 +1,10 @@ -import { Amount } from "."; +import { Amount } from "../common"; interface CreatedNode { CreatedNode: { LedgerEntryType: string; LedgerIndex: string; - NewFields: { [field: string]: any }; + NewFields: { [field: string]: unknown }; }; } @@ -12,8 +12,8 @@ interface ModifiedNode { ModifiedNode: { LedgerEntryType: string; LedgerIndex: string; - FinalFields: { [field: string]: any }; - PreviousFields: { [field: string]: any }; + FinalFields: { [field: string]: unknown }; + PreviousFields: { [field: string]: unknown }; PreviousTxnID?: string; PreviouTxnLgrSeq?: number; }; @@ -23,13 +23,13 @@ interface DeletedNode { DeletedNode: { LedgerEntryType: string; LedgerIndex: string; - FinalFields: { [field: string]: any }; + FinalFields: { [field: string]: unknown }; }; } type Node = CreatedNode | ModifiedNode | DeletedNode; -export default interface Metadata { +export default interface TransactionMetadata { AffectedNodes: Node[]; DeliveredAmount?: Amount; delivered_amount?: Amount; diff --git a/src/models/transactions/offerCancel.ts b/src/models/transactions/offerCancel.ts index c4615747..74839603 100644 --- a/src/models/transactions/offerCancel.ts +++ b/src/models/transactions/offerCancel.ts @@ -11,10 +11,9 @@ export interface OfferCancel extends BaseTransaction { * Verify the form and type of an OfferCancel at runtime. * * @param tx - An OfferCancel Transaction. - * @returns Void. * @throws When the OfferCancel is Malformed. */ -export function verifyOfferCancel(tx: OfferCancel): void { +export function verifyOfferCancel(tx: Record): void { verifyBaseTransaction(tx); if (tx.OfferSequence === undefined) { diff --git a/src/models/transactions/offerCreate.ts b/src/models/transactions/offerCreate.ts index b926f269..52fa9df5 100644 --- a/src/models/transactions/offerCreate.ts +++ b/src/models/transactions/offerCreate.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyOfferCreate */ import { ValidationError } from "../../common/errors"; import { Amount } from "../common"; @@ -28,10 +29,9 @@ export interface OfferCreate extends BaseTransaction { * Verify the form and type of an OfferCreate at runtime. * * @param tx - An OfferCreate Transaction. - * @returns Void. * @throws When the OfferCreate is Malformed. */ -export function verifyOfferCreate(tx: OfferCreate): void { +export function verifyOfferCreate(tx: Record): void { verifyBaseTransaction(tx); if (tx.TakerGets === undefined) { diff --git a/src/models/transactions/paymentTransaction.ts b/src/models/transactions/payment.ts similarity index 52% rename from src/models/transactions/paymentTransaction.ts rename to src/models/transactions/payment.ts index 7797a1ea..0926eb5c 100644 --- a/src/models/transactions/paymentTransaction.ts +++ b/src/models/transactions/payment.ts @@ -1,3 +1,5 @@ +/* eslint-disable max-statements -- Necessary for verifyPayment */ +/* eslint-disable complexity -- Necessary for verifyPayment */ import { ValidationError } from "../../common/errors"; import { Amount, Path } from "../common"; import { isFlagEnabled } from "../utils"; @@ -20,7 +22,7 @@ export interface PaymentTransactionFlags extends GlobalFlags { tfPartialPayment?: boolean; tfLimitQuality?: boolean; } -export interface PaymentTransaction extends BaseTransaction { +export interface Payment extends BaseTransaction { TransactionType: "Payment"; Amount: Amount; Destination: string; @@ -33,11 +35,12 @@ export interface PaymentTransaction extends BaseTransaction { } /** + * Verify the form and type of a Payment at runtime. + * * @param tx - A Payment Transaction. - * @returns - * @throws {ValidationError} When the PaymentTransaction is malformed. + * @throws When the Payment is malformed. */ -export function verifyPaymentTransaction(tx: PaymentTransaction): void { +export function verifyPayment(tx: Record): void { verifyBaseTransaction(tx); if (tx.Amount === undefined) { @@ -69,7 +72,11 @@ export function verifyPaymentTransaction(tx: PaymentTransaction): void { throw new ValidationError("PaymentTransaction: InvoiceID must be a string"); } - if (tx.Paths !== undefined && !isPaths(tx.Paths)) { + if ( + tx.Paths !== undefined && + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + !isPaths(tx.Paths as Array>>) + ) { throw new ValidationError("PaymentTransaction: invalid Paths"); } @@ -77,11 +84,23 @@ export function verifyPaymentTransaction(tx: PaymentTransaction): void { throw new ValidationError("PaymentTransaction: invalid SendMax"); } - if (tx.DeliverMin !== undefined) { + checkPartialPayment(tx); +} + +function checkPartialPayment(tx: Record): void { + if (tx.DeliverMin != null) { + if (tx.Flags == null) { + throw new ValidationError( + "PaymentTransaction: tfPartialPayment flag required with DeliverMin" + ); + } + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + const flags = tx.Flags as number | PaymentTransactionFlags; const isTfPartialPayment = - typeof tx.Flags === "number" - ? isFlagEnabled(tx.Flags, PaymentTransactionFlagsEnum.tfPartialPayment) - : tx.Flags?.tfPartialPayment ?? false; + typeof flags === "number" + ? isFlagEnabled(flags, PaymentTransactionFlagsEnum.tfPartialPayment) + : flags.tfPartialPayment ?? false; if (!isTfPartialPayment) { throw new ValidationError( @@ -95,27 +114,53 @@ export function verifyPaymentTransaction(tx: PaymentTransaction): void { } } -function isPaths(paths: Path[]): boolean { +function isPathStep(pathStep: Record): boolean { + if (pathStep.account !== undefined && typeof pathStep.account !== "string") { + return false; + } + if ( + pathStep.currency !== undefined && + typeof pathStep.currency !== "string" + ) { + return false; + } + if (pathStep.issuer !== undefined && typeof pathStep.issuer !== "string") { + return false; + } + if ( + pathStep.account !== undefined && + pathStep.currency === undefined && + pathStep.issuer === undefined + ) { + return true; + } + if (pathStep.currency !== undefined || pathStep.issuer !== undefined) { + return true; + } + return false; +} + +function isPath(path: Array>): boolean { + for (const pathStep of path) { + if (!isPathStep(pathStep)) { + return false; + } + } + return true; +} + +function isPaths(paths: Array>>): boolean { if (!Array.isArray(paths) || paths.length === 0) { return false; } - for (const i in paths) { - const path = paths[i]; + for (const path of paths) { if (!Array.isArray(path) || path.length === 0) { return false; } - for (const j in path) { - const pathStep = path[j]; - const { account, currency, issuer } = pathStep; - if ( - (account !== undefined && typeof account !== "string") || - (currency !== undefined && typeof currency !== "string") || - (issuer !== undefined && typeof issuer !== "string") - ) { - return false; - } + if (!isPath(path)) { + return false; } } diff --git a/src/models/transactions/paymentChannelClaim.ts b/src/models/transactions/paymentChannelClaim.ts index a8a6b8fe..89d65bfb 100644 --- a/src/models/transactions/paymentChannelClaim.ts +++ b/src/models/transactions/paymentChannelClaim.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyPaymentChannelClaim */ import { ValidationError } from "../../common/errors"; import { BaseTransaction, GlobalFlags, verifyBaseTransaction } from "./common"; @@ -21,10 +22,9 @@ export interface PaymentChannelClaim extends BaseTransaction { * Verify the form and type of an PaymentChannelClaim at runtime. * * @param tx - An PaymentChannelClaim Transaction. - * @returns Void. * @throws When the PaymentChannelClaim is Malformed. */ -export function verifyPaymentChannelClaim(tx: PaymentChannelClaim): void { +export function verifyPaymentChannelClaim(tx: Record): void { verifyBaseTransaction(tx); if (tx.Channel === undefined) { diff --git a/src/models/transactions/paymentChannelCreate.ts b/src/models/transactions/paymentChannelCreate.ts index 56ae2424..4fac858c 100644 --- a/src/models/transactions/paymentChannelCreate.ts +++ b/src/models/transactions/paymentChannelCreate.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity -- Necessary for verifyPaymentChannelCreate */ import { ValidationError } from "../../common/errors"; import { BaseTransaction, verifyBaseTransaction } from "./common"; @@ -16,10 +17,9 @@ export interface PaymentChannelCreate extends BaseTransaction { * Verify the form and type of an PaymentChannelCreate at runtime. * * @param tx - An PaymentChannelCreate Transaction. - * @returns Void. * @throws When the PaymentChannelCreate is Malformed. */ -export function verifyPaymentChannelCreate(tx: PaymentChannelCreate): void { +export function verifyPaymentChannelCreate(tx: Record): void { verifyBaseTransaction(tx); if (tx.Amount === undefined) { diff --git a/src/models/transactions/paymentChannelFund.ts b/src/models/transactions/paymentChannelFund.ts index 320e2957..5558fb04 100644 --- a/src/models/transactions/paymentChannelFund.ts +++ b/src/models/transactions/paymentChannelFund.ts @@ -13,10 +13,9 @@ export interface PaymentChannelFund extends BaseTransaction { * Verify the form and type of an PaymentChannelFund at runtime. * * @param tx - An PaymentChannelFund Transaction. - * @returns Void. * @throws When the PaymentChannelFund is Malformed. */ -export function verifyPaymentChannelFund(tx: PaymentChannelFund): void { +export function verifyPaymentChannelFund(tx: Record): void { verifyBaseTransaction(tx); if (tx.Channel === undefined) { diff --git a/src/models/transactions/setRegularKey.ts b/src/models/transactions/setRegularKey.ts index 5bbd9f28..31481e71 100644 --- a/src/models/transactions/setRegularKey.ts +++ b/src/models/transactions/setRegularKey.ts @@ -8,11 +8,12 @@ export interface SetRegularKey extends BaseTransaction { } /** - * @param tx - A Payment Transaction. - * @returns - * @throws {ValidationError} When the SetRegularKey is malformed. + * Verify the form and type of a SetRegularKey at runtime. + * + * @param tx - A SetRegularKey Transaction. + * @throws When the SetRegularKey is malformed. */ -export function verifySetRegularKey(tx: SetRegularKey): void { +export function verifySetRegularKey(tx: Record): void { verifyBaseTransaction(tx); if (tx.RegularKey !== undefined && typeof tx.RegularKey !== "string") { diff --git a/src/models/transactions/signerListSet.ts b/src/models/transactions/signerListSet.ts index 245e814a..e0eb86ed 100644 --- a/src/models/transactions/signerListSet.ts +++ b/src/models/transactions/signerListSet.ts @@ -9,14 +9,15 @@ export interface SignerListSet extends BaseTransaction { SignerEntries: SignerEntry[]; } +const MAX_SIGNERS = 8; + /** * Verify the form and type of an SignerListSet at runtime. * * @param tx - An SignerListSet Transaction. - * @returns Void. * @throws When the SignerListSet is Malformed. */ -export function verifySignerListSet(tx: SignerListSet): void { +export function verifySignerListSet(tx: Record): void { verifyBaseTransaction(tx); if (tx.SignerQuorum === undefined) { @@ -41,7 +42,7 @@ export function verifySignerListSet(tx: SignerListSet): void { ); } - if (tx.SignerEntries.length > 8) { + if (tx.SignerEntries.length > MAX_SIGNERS) { throw new ValidationError( "SignerListSet: maximum of 8 members allowed in SignerEntries" ); diff --git a/src/models/transactions/ticketCreate.ts b/src/models/transactions/ticketCreate.ts index 109f69f3..d8be778f 100644 --- a/src/models/transactions/ticketCreate.ts +++ b/src/models/transactions/ticketCreate.ts @@ -7,13 +7,15 @@ export interface TicketCreate extends BaseTransaction { TicketCount: number; } +const MAX_TICKETS = 250; + /** + * Verify the form and type of a TicketCreate at runtime. * * @param tx - A TicketCreate Transaction. - * @returns - * @throws {ValidationError} When the TicketCreate is malformed. + * @throws When the TicketCreate is malformed. */ -export function verifyTicketCreate(tx: TicketCreate): void { +export function verifyTicketCreate(tx: Record): void { verifyBaseTransaction(tx); const { TicketCount } = tx; @@ -25,7 +27,11 @@ export function verifyTicketCreate(tx: TicketCreate): void { throw new ValidationError("TicketCreate: TicketCount must be a number"); } - if (!Number.isInteger(TicketCount) || TicketCount < 1 || TicketCount > 250) { + if ( + !Number.isInteger(TicketCount) || + TicketCount < 1 || + TicketCount > MAX_TICKETS + ) { throw new ValidationError( "TicketCreate: TicketCount must be an integer from 1 to 250" ); diff --git a/src/models/transactions/transaction.ts b/src/models/transactions/transaction.ts index 0ed240a7..09385d53 100644 --- a/src/models/transactions/transaction.ts +++ b/src/models/transactions/transaction.ts @@ -1,4 +1,4 @@ -import Metadata from "../common/metadata"; +/* eslint-disable import/max-dependencies -- All methods need to be exported */ import { AccountDelete } from "./accountDelete"; import { AccountSet } from "./accountSet"; @@ -9,12 +9,13 @@ import { DepositPreauth } from "./depositPreauth"; import { EscrowCancel } from "./escrowCancel"; import { EscrowCreate } from "./escrowCreate"; import { EscrowFinish } from "./escrowFinish"; +import Metadata from "./metadata"; import { OfferCancel } from "./offerCancel"; import { OfferCreate } from "./offerCreate"; +import { Payment } from "./payment"; import { PaymentChannelClaim } from "./paymentChannelClaim"; import { PaymentChannelCreate } from "./paymentChannelCreate"; import { PaymentChannelFund } from "./paymentChannelFund"; -import { PaymentTransaction } from "./paymentTransaction"; import { SetRegularKey } from "./setRegularKey"; import { SignerListSet } from "./signerListSet"; import { TicketCreate } from "./ticketCreate"; @@ -32,7 +33,7 @@ export type Transaction = | EscrowFinish | OfferCancel | OfferCreate - | PaymentTransaction + | Payment | PaymentChannelClaim | PaymentChannelCreate | PaymentChannelFund diff --git a/src/models/transactions/trustSet.ts b/src/models/transactions/trustSet.ts index e43c31ac..e149de6e 100644 --- a/src/models/transactions/trustSet.ts +++ b/src/models/transactions/trustSet.ts @@ -33,12 +33,12 @@ export interface TrustSet extends BaseTransaction { } /** + * Verify the form and type of a TrustSet at runtime. * * @param tx - A TrustSet Transaction. - * @returns - * @throws {ValidationError} When the TrustSet is malformed. + * @throws When the TrustSet is malformed. */ -export function verifyTrustSet(tx: TrustSet): void { +export function verifyTrustSet(tx: Record): void { verifyBaseTransaction(tx); const { LimitAmount, QualityIn, QualityOut } = tx; diff --git a/src/models/utils/index.ts b/src/models/utils/index.ts index 4901c1ae..5c1ce128 100644 --- a/src/models/utils/index.ts +++ b/src/models/utils/index.ts @@ -5,7 +5,10 @@ * @param fields - Fields to verify. * @returns True if keys in object are all in fields. */ -export function onlyHasFields(obj: object, fields: string[]): boolean { +export function onlyHasFields( + obj: Record, + fields: string[] +): boolean { return Object.keys(obj).every((key: string) => fields.includes(key)); } @@ -17,5 +20,6 @@ export function onlyHasFields(obj: object, fields: string[]): boolean { * @returns True if checkFlag is enabled within Flags. */ export function isFlagEnabled(Flags: number, checkFlag: number): boolean { + // eslint-disable-next-line no-bitwise -- Flags require bitwise operations return (checkFlag & Flags) === checkFlag; } diff --git a/test/models/paymentTransaction.ts b/test/models/payment.ts similarity index 77% rename from test/models/paymentTransaction.ts rename to test/models/payment.ts index c28d0e75..c7a9dd52 100644 --- a/test/models/paymentTransaction.ts +++ b/test/models/payment.ts @@ -4,8 +4,8 @@ import { ValidationError } from "xrpl-local/common/errors"; import { PaymentTransactionFlagsEnum, - verifyPaymentTransaction, -} from "../../src/models/transactions/paymentTransaction"; + verifyPayment, +} from "../../src/models/transactions/payment"; /** * PaymentTransaction Verification Testing. @@ -24,21 +24,19 @@ describe("Payment Transaction Verification", function () { DestinationTag: 1, InvoiceID: "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B", - Paths: [ - [{ account: "aw0efji", currency: "XRP", issuer: "apsoeijf90wp34fh" }], - ], + Paths: [[{ currency: "BTC", issuer: "apsoeijf90wp34fh" }]], SendMax: "100000000", } as any; }); it(`verifies valid PaymentTransaction`, function () { - assert.doesNotThrow(() => verifyPaymentTransaction(paymentTransaction)); + assert.doesNotThrow(() => verifyPayment(paymentTransaction)); }); it(`throws when Amount is missing`, function () { delete paymentTransaction.Amount; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: missing field Amount" ); @@ -47,7 +45,7 @@ describe("Payment Transaction Verification", function () { it(`throws when Amount is invalid`, function () { paymentTransaction.Amount = 1234; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: invalid Amount" ); @@ -56,7 +54,7 @@ describe("Payment Transaction Verification", function () { it(`throws when Destination is missing`, function () { delete paymentTransaction.Destination; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: missing field Destination" ); @@ -65,7 +63,7 @@ describe("Payment Transaction Verification", function () { it(`throws when Destination is invalid`, function () { paymentTransaction.Destination = 7896214; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: invalid Destination" ); @@ -74,7 +72,7 @@ describe("Payment Transaction Verification", function () { it(`throws when DestinationTag is not a number`, function () { paymentTransaction.DestinationTag = "1"; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: DestinationTag must be a number" ); @@ -83,7 +81,7 @@ describe("Payment Transaction Verification", function () { it(`throws when InvoiceID is not a string`, function () { paymentTransaction.InvoiceID = 19832; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: InvoiceID must be a string" ); @@ -92,7 +90,7 @@ describe("Payment Transaction Verification", function () { it(`throws when Paths is invalid`, function () { paymentTransaction.Paths = [[{ account: 123 }]]; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: invalid Paths" ); @@ -101,7 +99,7 @@ describe("Payment Transaction Verification", function () { it(`throws when SendMax is invalid`, function () { paymentTransaction.SendMax = 100000000; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: invalid SendMax" ); @@ -110,20 +108,20 @@ describe("Payment Transaction Verification", function () { it(`verifies valid DeliverMin with tfPartialPayment flag set as a number`, function () { paymentTransaction.DeliverMin = "10000"; (paymentTransaction.Flags = PaymentTransactionFlagsEnum.tfPartialPayment), - assert.doesNotThrow(() => verifyPaymentTransaction(paymentTransaction)); + assert.doesNotThrow(() => verifyPayment(paymentTransaction)); }); it(`verifies valid DeliverMin with tfPartialPayment flag set as a boolean`, function () { paymentTransaction.DeliverMin = "10000"; paymentTransaction.Flags = { tfPartialPayment: true }; - assert.doesNotThrow(() => verifyPaymentTransaction(paymentTransaction)); + assert.doesNotThrow(() => verifyPayment(paymentTransaction)); }); it(`throws when DeliverMin is invalid`, function () { paymentTransaction.DeliverMin = 10000; paymentTransaction.Flags = { tfPartialPayment: true }; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: invalid DeliverMin" ); @@ -132,7 +130,7 @@ describe("Payment Transaction Verification", function () { it(`throws when tfPartialPayment flag is missing with valid DeliverMin`, function () { paymentTransaction.DeliverMin = "10000"; assert.throws( - () => verifyPaymentTransaction(paymentTransaction), + () => verifyPayment(paymentTransaction), ValidationError, "PaymentTransaction: tfPartialPayment flag required with DeliverMin" ); diff --git a/test/models/utils.ts b/test/models/utils.ts index c3c33476..4f329d6f 100644 --- a/test/models/utils.ts +++ b/test/models/utils.ts @@ -9,7 +9,7 @@ import { isFlagEnabled } from "../../src/models/utils"; */ describe("Models Utils", function () { describe("isFlagEnabled", function () { - let flags; + let flags: number; const flag1 = 0x00010000; const flag2 = 0x00020000;