refactor: type Transaction to include all tx (#2547)

refactor: type Transaction to include all tx

BREAKING CHANGE: `Transaction` type has been redefined to include all
transactions and `SubmittableTransaction` was created to define the old
value. The following functions which only handle transactions to be
submitted now use `SubmittableTransaction`:
  * `Client.autofill`
  * `Client.submit`
  * `Client.submitAndWait`
  * `Client.prepareTransaction`
  * `getSignedTx`
  * `isAccountDelete`
This commit is contained in:
Caleb Kniffen
2023-11-01 16:07:16 -05:00
parent fa4eabef0e
commit 3f1739895a
12 changed files with 61 additions and 43 deletions

View File

@@ -4,6 +4,15 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
## Unreleased ## Unreleased
### Breaking Changes
* `Transaction` type has been redefined to include all transactions and `SubmittableTransaction` was created to define the old value. The following functions which only handle transactions to be submitted now use `SubmittableTransaction`:
* `Client.autofill`
* `Client.submit`
* `Client.submitAndWait`
* `Client.prepareTransaction`
* `getSignedTx`
* `isAccountDelete`
## 3.0.0 Beta 1 (2023-10-19) ## 3.0.0 Beta 1 (2023-10-19)
### Breaking Changes ### Breaking Changes

View File

@@ -41,7 +41,7 @@ import type {
EventTypes, EventTypes,
OnEventToListenerMap, OnEventToListenerMap,
} from '../models/methods/subscribe' } from '../models/methods/subscribe'
import type { Transaction } from '../models/transactions' import type { SubmittableTransaction } from '../models/transactions'
import { setTransactionFlagsToNumber } from '../models/utils/flags' import { setTransactionFlagsToNumber } from '../models/utils/flags'
import { import {
ensureClassicAddress, ensureClassicAddress,
@@ -623,12 +623,12 @@ class Client extends EventEmitter<EventTypes> {
* in an unsigned transaction along with your wallet to be submitted. * in an unsigned transaction along with your wallet to be submitted.
* *
* @template T * @template T
* @param transaction - A {@link Transaction} in JSON format * @param transaction - A {@link SubmittableTransaction} in JSON format
* @param signersCount - The expected number of signers for this transaction. * @param signersCount - The expected number of signers for this transaction.
* Only used for multisigned transactions. * Only used for multisigned transactions.
* @returns The autofilled transaction. * @returns The autofilled transaction.
*/ */
public async autofill<T extends Transaction>( public async autofill<T extends SubmittableTransaction>(
transaction: T, transaction: T,
signersCount?: number, signersCount?: number,
): Promise<T> { ): Promise<T> {
@@ -693,7 +693,7 @@ class Client extends EventEmitter<EventTypes> {
* ``` * ```
*/ */
public async submit( public async submit(
transaction: Transaction | string, transaction: SubmittableTransaction | string,
opts?: { opts?: {
// If true, autofill a transaction. // If true, autofill a transaction.
autofill?: boolean autofill?: boolean
@@ -764,7 +764,9 @@ class Client extends EventEmitter<EventTypes> {
* ledger, the promise returned by `submitAndWait()` will be rejected with an error. * ledger, the promise returned by `submitAndWait()` will be rejected with an error.
* @returns A promise that contains TxResponse, that will return when the transaction has been validated. * @returns A promise that contains TxResponse, that will return when the transaction has been validated.
*/ */
public async submitAndWait<T extends Transaction = Transaction>( public async submitAndWait<
T extends SubmittableTransaction = SubmittableTransaction,
>(
transaction: T | string, transaction: T | string,
opts?: { opts?: {
// If true, autofill a transaction. // If true, autofill a transaction.
@@ -804,7 +806,7 @@ class Client extends EventEmitter<EventTypes> {
* @deprecated Use autofill instead, provided for users familiar with v1 * @deprecated Use autofill instead, provided for users familiar with v1
*/ */
public async prepareTransaction( public async prepareTransaction(
transaction: Transaction, transaction: SubmittableTransaction,
signersCount?: number, signersCount?: number,
): ReturnType<Client['autofill']> { ): ReturnType<Client['autofill']> {
return this.autofill(transaction, signersCount) return this.autofill(transaction, signersCount)

View File

@@ -10,11 +10,7 @@ import type {
import type { Amount } from '../models/common' import type { Amount } from '../models/common'
import type { RequestResponseMap } from '../models/methods' import type { RequestResponseMap } from '../models/methods'
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod' import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
import { import { PaymentFlags, Transaction } from '../models/transactions'
PaymentFlags,
PseudoTransaction,
Transaction,
} from '../models/transactions'
import type { TransactionMetadata } from '../models/transactions/metadata' import type { TransactionMetadata } from '../models/transactions/metadata'
import { isFlagEnabled } from '../models/utils' import { isFlagEnabled } from '../models/utils'
@@ -40,7 +36,7 @@ function amountsEqual(amt1: Amount, amt2: Amount): boolean {
} }
function isPartialPayment( function isPartialPayment(
tx?: Transaction | PseudoTransaction, tx?: Transaction,
metadata?: TransactionMetadata | string, metadata?: TransactionMetadata | string,
): boolean { ): boolean {
if (tx == null || metadata == null || tx.TransactionType !== 'Payment') { if (tx == null || metadata == null || tx.TransactionType !== 'Payment') {

View File

@@ -1,8 +1,4 @@
import { import { Transaction, TransactionMetadata } from '../transactions'
PseudoTransaction,
Transaction,
TransactionMetadata,
} from '../transactions'
import { LedgerEntry } from './LedgerEntry' import { LedgerEntry } from './LedgerEntry'
@@ -65,7 +61,5 @@ export default interface Ledger {
* either JSON or binary depending on whether the request specified binary * either JSON or binary depending on whether the request specified binary
* as true. * as true.
*/ */
transactions?: Array< transactions?: Array<Transaction & { metaData?: TransactionMetadata }>
(Transaction | PseudoTransaction) & { metaData?: TransactionMetadata }
>
} }

View File

@@ -1,4 +1,4 @@
import { Transaction } from '../transactions' import { SubmittableTransaction } from '../transactions'
import { BaseRequest, BaseResponse } from './baseMethod' import { BaseRequest, BaseResponse } from './baseMethod'
@@ -39,7 +39,7 @@ export interface SubmitResponse extends BaseResponse {
/** The complete transaction in hex string format. */ /** The complete transaction in hex string format. */
tx_blob: string tx_blob: string
/** The complete transaction in JSON format. */ /** The complete transaction in JSON format. */
tx_json: Transaction & { hash?: string } tx_json: SubmittableTransaction & { hash?: string }
/** /**
* The value true indicates that the transaction was applied, queued, * The value true indicates that the transaction was applied, queued,
* broadcast, or kept for later. The value `false` indicates that none of * broadcast, or kept for later. The value `false` indicates that none of

View File

@@ -1,6 +1,5 @@
import { Transaction, TransactionMetadata } from '../transactions' import { Transaction, TransactionMetadata } from '../transactions'
import { BaseTransaction } from '../transactions/common' import { BaseTransaction } from '../transactions/common'
import { PseudoTransaction } from '../transactions/transaction'
import { BaseRequest, BaseResponse } from './baseMethod' import { BaseRequest, BaseResponse } from './baseMethod'
@@ -47,9 +46,8 @@ export interface TxRequest extends BaseRequest {
* *
* @category Responses * @category Responses
*/ */
export interface TxResponse< export interface TxResponse<T extends BaseTransaction = Transaction>
T extends BaseTransaction = Transaction | PseudoTransaction, extends BaseResponse {
> extends BaseResponse {
result: { result: {
/** The SHA-512 hash of the transaction. */ /** The SHA-512 hash of the transaction. */
hash: string hash: string

View File

@@ -2,6 +2,7 @@ export { BaseTransaction } from './common'
export { export {
validate, validate,
PseudoTransaction, PseudoTransaction,
SubmittableTransaction,
TransactionAndMetadata, TransactionAndMetadata,
Transaction, Transaction,
} from './transaction' } from './transaction'

View File

@@ -90,9 +90,11 @@ import {
} from './XChainModifyBridge' } from './XChainModifyBridge'
/** /**
* Transactions that can be submitted by clients
*
* @category Transaction Models * @category Transaction Models
*/ */
export type Transaction = export type SubmittableTransaction =
| AMMBid | AMMBid
| AMMCreate | AMMCreate
| AMMDelete | AMMDelete
@@ -135,8 +137,20 @@ export type Transaction =
| XChainCreateClaimID | XChainCreateClaimID
| XChainModifyBridge | XChainModifyBridge
/**
* Transactions that can only be created by validators.
*
* @category Transaction Models
*/
export type PseudoTransaction = EnableAmendment | SetFee | UNLModify export type PseudoTransaction = EnableAmendment | SetFee | UNLModify
/**
* All transactions that can live on the XRPL
*
* @category Transaction Models
*/
export type Transaction = SubmittableTransaction | PseudoTransaction
/** /**
* @category Transaction Models * @category Transaction Models
*/ */

View File

@@ -1,10 +1,16 @@
import { decode, encode } from 'ripple-binary-codec' import { decode, encode } from 'ripple-binary-codec'
import type { Client, SubmitRequest, SubmitResponse, Wallet } from '..' import type {
Client,
SubmitRequest,
SubmitResponse,
SubmittableTransaction,
Transaction,
Wallet,
} from '..'
import { ValidationError, XrplError } from '../errors' import { ValidationError, XrplError } from '../errors'
import { Signer } from '../models/common' import { Signer } from '../models/common'
import { TxRequest, TxResponse } from '../models/methods' import { TxRequest, TxResponse } from '../models/methods'
import { Transaction } from '../models/transactions'
import { BaseTransaction } from '../models/transactions/common' import { BaseTransaction } from '../models/transactions/common'
/** Approximate time for a ledger to close, in milliseconds */ /** Approximate time for a ledger to close, in milliseconds */
@@ -42,7 +48,7 @@ async function sleep(ms: number): Promise<void> {
*/ */
export async function submitRequest( export async function submitRequest(
client: Client, client: Client,
signedTransaction: Transaction | string, signedTransaction: SubmittableTransaction | string,
failHard = false, failHard = false,
): Promise<SubmitResponse> { ): Promise<SubmitResponse> {
if (!isSigned(signedTransaction)) { if (!isSigned(signedTransaction)) {
@@ -104,7 +110,7 @@ export async function submitRequest(
*/ */
// eslint-disable-next-line max-params, max-lines-per-function -- this function needs to display and do with more information. // eslint-disable-next-line max-params, max-lines-per-function -- this function needs to display and do with more information.
export async function waitForFinalTransactionOutcome< export async function waitForFinalTransactionOutcome<
T extends BaseTransaction = Transaction, T extends BaseTransaction = SubmittableTransaction,
>( >(
client: Client, client: Client,
txHash: string, txHash: string,
@@ -159,7 +165,7 @@ export async function waitForFinalTransactionOutcome<
} }
// checks if the transaction has been signed // checks if the transaction has been signed
function isSigned(transaction: Transaction | string): boolean { function isSigned(transaction: SubmittableTransaction | string): boolean {
const tx = typeof transaction === 'string' ? decode(transaction) : transaction const tx = typeof transaction === 'string' ? decode(transaction) : transaction
if (typeof tx === 'string') { if (typeof tx === 'string') {
return false return false
@@ -218,7 +224,7 @@ function isSigned(transaction: Transaction | string): boolean {
*/ */
export async function getSignedTx( export async function getSignedTx(
client: Client, client: Client,
transaction: Transaction | string, transaction: SubmittableTransaction | string,
{ {
autofill = true, autofill = true,
wallet, wallet,
@@ -228,7 +234,7 @@ export async function getSignedTx(
// A wallet to sign a transaction. It must be provided when submitting an unsigned transaction. // A wallet to sign a transaction. It must be provided when submitting an unsigned transaction.
wallet?: Wallet wallet?: Wallet
} = {}, } = {},
): Promise<Transaction | string> { ): Promise<SubmittableTransaction | string> {
if (isSigned(transaction)) { if (isSigned(transaction)) {
return transaction return transaction
} }
@@ -242,7 +248,7 @@ export async function getSignedTx(
let tx = let tx =
typeof transaction === 'string' typeof transaction === 'string'
? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts JsonObject to correct Transaction type ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts JsonObject to correct Transaction type
(decode(transaction) as unknown as Transaction) (decode(transaction) as unknown as SubmittableTransaction)
: transaction : transaction
if (autofill) { if (autofill) {

View File

@@ -10,7 +10,6 @@ import { ValidationError, XrplError } from '../../errors'
import type { Ledger } from '../../models/ledger' import type { Ledger } from '../../models/ledger'
import { LedgerEntry } from '../../models/ledger' import { LedgerEntry } from '../../models/ledger'
import { Transaction, TransactionMetadata } from '../../models/transactions' import { Transaction, TransactionMetadata } from '../../models/transactions'
import { PseudoTransaction } from '../../models/transactions/transaction'
import HashPrefix from './HashPrefix' import HashPrefix from './HashPrefix'
import sha512Half from './sha512Half' import sha512Half from './sha512Half'
@@ -125,9 +124,7 @@ export function hashLedgerHeader(ledgerHeader: Ledger): string {
* @category Utilities * @category Utilities
*/ */
export function hashTxTree( export function hashTxTree(
transactions: Array< transactions: Array<Transaction & { metaData?: TransactionMetadata }>,
(Transaction | PseudoTransaction) & { metaData?: TransactionMetadata }
>,
): string { ): string {
const shamap = new SHAMap() const shamap = new SHAMap()
for (const txJSON of transactions) { for (const txJSON of transactions) {

View File

@@ -6,7 +6,7 @@ import {
SubmitRequest, SubmitRequest,
SubmitResponse, SubmitResponse,
hashes, hashes,
Transaction, SubmittableTransaction,
} from '../../../src' } from '../../../src'
import { convertStringToHex } from '../../../src/utils' import { convertStringToHex } from '../../../src/utils'
import serverUrl from '../serverUrl' import serverUrl from '../serverUrl'
@@ -63,7 +63,7 @@ describe('submit', function () {
'The transaction was applied. Only final in a validated ledger.', 'The transaction was applied. Only final in a validated ledger.',
tx_blob: signedTx.tx_blob, tx_blob: signedTx.tx_blob,
tx_json: { tx_json: {
...(decode(signedTx.tx_blob) as unknown as Transaction), ...(decode(signedTx.tx_blob) as unknown as SubmittableTransaction),
hash: hashSignedTx(signedTx.tx_blob), hash: hashSignedTx(signedTx.tx_blob),
}, },
accepted: true, accepted: true,

View File

@@ -20,6 +20,7 @@ import {
AccountSet, AccountSet,
AccountSetAsfFlags, AccountSetAsfFlags,
Payment, Payment,
SubmittableTransaction,
Transaction, Transaction,
TrustSet, TrustSet,
TrustSetFlags, TrustSetFlags,
@@ -98,7 +99,7 @@ export async function submitTransaction({
retry = { count: 5, delayMs: 1000 }, retry = { count: 5, delayMs: 1000 },
}: { }: {
client: Client client: Client
transaction: Transaction transaction: SubmittableTransaction
wallet: Wallet wallet: Wallet
retry?: { retry?: {
count: number count: number
@@ -234,7 +235,7 @@ export async function verifySubmittedTransaction(
// eslint-disable-next-line max-params -- Test function, many params are needed // eslint-disable-next-line max-params -- Test function, many params are needed
export async function testTransaction( export async function testTransaction(
client: Client, client: Client,
transaction: Transaction, transaction: SubmittableTransaction,
wallet: Wallet, wallet: Wallet,
retry?: { retry?: {
count: number count: number