diff --git a/packages/xrpl/src/models/transactions/AMMBid.ts b/packages/xrpl/src/models/transactions/AMMBid.ts index 50657729d1..76a5eb9435 100644 --- a/packages/xrpl/src/models/transactions/AMMBid.ts +++ b/packages/xrpl/src/models/transactions/AMMBid.ts @@ -65,6 +65,7 @@ export interface AMMBid extends BaseTransaction { * @param tx - An AMMBid Transaction. * @throws When the AMMBid is Malformed. */ +// eslint-disable-next-line max-lines-per-function -- necessary for validateAMMBid export function validateAMMBid(tx: Record): void { validateBaseTransaction(tx) @@ -103,5 +104,48 @@ export function validateAMMBid(tx: Record): void { `AMMBid: AuthAccounts length must not be greater than ${MAX_AUTH_ACCOUNTS}`, ) } + if ( + !isAuthAccounts( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + tx.Account as string, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Only used by JS + tx.AuthAccounts as Array>, + ) + ) { + throw new ValidationError(`AMMBid: invalid AuthAccounts`) + } + } +} + +function isAuthAccounts( + senderAddress: string, + authAccounts: Array>, +): boolean { + for (const authAccount of authAccounts) { + if ( + authAccount.AuthAccount == null || + typeof authAccount.AuthAccount !== 'object' + ) { + return false + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check + // @ts-expect-error -- used for null check + if (authAccount.AuthAccount.Account == null) { + return false + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check + // @ts-expect-error -- used for null check + if (typeof authAccount.AuthAccount.Account !== 'string') { + return false + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- used for null check + // @ts-expect-error -- used for null check + if (authAccount.AuthAccount.Account === senderAddress) { + throw new ValidationError( + `AMMBid: AuthAccounts must not include sender's address`, + ) + } } + + return true } diff --git a/packages/xrpl/test/models/AMMBid.test.ts b/packages/xrpl/test/models/AMMBid.test.ts index e06dac8f27..9bbc76ee6e 100644 --- a/packages/xrpl/test/models/AMMBid.test.ts +++ b/packages/xrpl/test/models/AMMBid.test.ts @@ -108,4 +108,61 @@ describe('AMMBid', function () { assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) assert.throws(() => validate(bid), ValidationError, errorMessage) }) + + it(`throws w/ AuthAccounts must be an AuthAccount array`, function () { + bid.AuthAccounts = 1234 + const errorMessage = 'AMMBid: AuthAccounts must be an AuthAccount array' + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) + + it(`throws w/ invalid AuthAccounts when AuthAccount is null`, function () { + bid.AuthAccounts[0] = { + AuthAccount: null, + } + const errorMessage = 'AMMBid: invalid AuthAccounts' + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) + + it(`throws w/ invalid AuthAccounts when AuthAccount is undefined`, function () { + bid.AuthAccounts[0] = { + AuthAccount: undefined, + } + const errorMessage = 'AMMBid: invalid AuthAccounts' + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) + + it(`throws w/ invalid AuthAccounts when AuthAccount is not an object`, function () { + bid.AuthAccounts[0] = { + AuthAccount: 1234, + } + const errorMessage = 'AMMBid: invalid AuthAccounts' + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) + + it(`throws w/ invalid AuthAccounts when AuthAccount.Account is not a string`, function () { + bid.AuthAccounts[0] = { + AuthAccount: { + Account: 1234, + }, + } + const errorMessage = 'AMMBid: invalid AuthAccounts' + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) + + it(`throws w/ AuthAccounts must not include sender's address`, function () { + bid.AuthAccounts[0] = { + AuthAccount: { + Account: bid.Account, + }, + } + const errorMessage = + "AMMBid: AuthAccounts must not include sender's address" + assert.throws(() => validateAMMBid(bid), ValidationError, errorMessage) + assert.throws(() => validate(bid), ValidationError, errorMessage) + }) })