mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-04 13:05:49 +00:00
Aliter: Implement DeliverMax alias in Payment transactions, through autofill method (#2689)
Co-authored-by: Omar Khan <khancodegt@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a0678857a1
commit
39fed49654
@@ -226,7 +226,7 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
* const client = new Client('wss://s.altnet.rippletest.net:51233')
|
* const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line max-lines-per-function -- okay because we have to set up all the connection handlers
|
/* eslint-disable max-lines-per-function -- the constructor requires more lines to implement the logic */
|
||||||
public constructor(server: string, options: ClientOptions = {}) {
|
public constructor(server: string, options: ClientOptions = {}) {
|
||||||
super()
|
super()
|
||||||
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
|
if (typeof server !== 'string' || !/wss?(?:\+unix)?:\/\//u.exec(server)) {
|
||||||
@@ -290,6 +290,7 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
this.emit('path_find', path)
|
this.emit('path_find', path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/* eslint-enable max-lines-per-function */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the url that the client is connected to.
|
* Get the url that the client is connected to.
|
||||||
@@ -638,7 +639,10 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
* @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.
|
||||||
|
* @throws ValidationError If Amount and DeliverMax fields are not identical in a Payment Transaction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity -- handling Payment transaction API v2 requires more logic
|
||||||
public async autofill<T extends SubmittableTransaction>(
|
public async autofill<T extends SubmittableTransaction>(
|
||||||
transaction: T,
|
transaction: T,
|
||||||
signersCount?: number,
|
signersCount?: number,
|
||||||
@@ -646,7 +650,6 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
const tx = { ...transaction }
|
const tx = { ...transaction }
|
||||||
|
|
||||||
setValidAddresses(tx)
|
setValidAddresses(tx)
|
||||||
|
|
||||||
setTransactionFlagsToNumber(tx)
|
setTransactionFlagsToNumber(tx)
|
||||||
|
|
||||||
const promises: Array<Promise<void>> = []
|
const promises: Array<Promise<void>> = []
|
||||||
@@ -666,6 +669,34 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
promises.push(checkAccountDeleteBlockers(this, tx))
|
promises.push(checkAccountDeleteBlockers(this, tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
|
||||||
|
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
|
||||||
|
if (tx.TransactionType === 'Payment' && tx.DeliverMax != null) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount
|
||||||
|
if (tx.Amount == null) {
|
||||||
|
// If only DeliverMax is provided, use it to populate the Amount field
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
|
||||||
|
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- DeliverMax is a known RPC-level property
|
||||||
|
tx.Amount = tx.DeliverMax
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
|
||||||
|
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- This is a valid null check for Amount
|
||||||
|
if (tx.Amount != null && tx.Amount !== tx.DeliverMax) {
|
||||||
|
return Promise.reject(
|
||||||
|
new ValidationError(
|
||||||
|
'PaymentTransaction: Amount and DeliverMax fields must be identical when both are provided',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type-assertions on the DeliverMax property
|
||||||
|
// @ts-expect-error -- DeliverMax property exists only at the RPC level, not at the protocol level
|
||||||
|
delete tx.DeliverMax
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(() => tx)
|
return Promise.all(promises).then(() => tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,7 +940,7 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
* @param options.limit - Limit number of balances to return.
|
* @param options.limit - Limit number of balances to return.
|
||||||
* @returns An array of XRP/non-XRP balances for the given account.
|
* @returns An array of XRP/non-XRP balances for the given account.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line max-lines-per-function -- Longer definition is required for end users to see the definition.
|
/* eslint-disable max-lines-per-function -- getBalances requires more lines to implement logic */
|
||||||
public async getBalances(
|
public async getBalances(
|
||||||
address: string,
|
address: string,
|
||||||
options: {
|
options: {
|
||||||
@@ -957,6 +988,7 @@ class Client extends EventEmitter<EventTypes> {
|
|||||||
)
|
)
|
||||||
return balances.slice(0, options.limit)
|
return balances.slice(0, options.limit)
|
||||||
}
|
}
|
||||||
|
/* eslint-enable max-lines-per-function */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch orderbook (buy/sell orders) between two currency pairs. This checks both sides of the orderbook
|
* Fetch orderbook (buy/sell orders) between two currency pairs. This checks both sides of the orderbook
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Payment,
|
Payment,
|
||||||
Transaction,
|
Transaction,
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
|
import { ValidationError } from '../../src/errors'
|
||||||
import rippled from '../fixtures/rippled'
|
import rippled from '../fixtures/rippled'
|
||||||
import {
|
import {
|
||||||
setupClient,
|
setupClient,
|
||||||
@@ -22,6 +23,8 @@ const LastLedgerSequence = 2908734
|
|||||||
|
|
||||||
describe('client.autofill', function () {
|
describe('client.autofill', function () {
|
||||||
let testContext: XrplTestContext
|
let testContext: XrplTestContext
|
||||||
|
const AMOUNT = '1234'
|
||||||
|
let paymentTx: Payment
|
||||||
|
|
||||||
async function setupMockRippledVersionAndID(
|
async function setupMockRippledVersionAndID(
|
||||||
buildVersion: string,
|
buildVersion: string,
|
||||||
@@ -40,10 +43,68 @@ describe('client.autofill', function () {
|
|||||||
await testContext.client.connect()
|
await testContext.client.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeAll(async () => {
|
||||||
testContext = await setupClient()
|
testContext = await setupClient()
|
||||||
})
|
})
|
||||||
afterEach(async () => teardownClient(testContext))
|
afterAll(async () => teardownClient(testContext))
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
paymentTx = {
|
||||||
|
TransactionType: 'Payment',
|
||||||
|
Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo',
|
||||||
|
Amount: AMOUNT,
|
||||||
|
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||||
|
DestinationTag: 1,
|
||||||
|
Fee: '12',
|
||||||
|
Flags: 2147483648,
|
||||||
|
LastLedgerSequence: 65953073,
|
||||||
|
Sequence: 65923914,
|
||||||
|
SigningPubKey:
|
||||||
|
'02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654',
|
||||||
|
TxnSignature:
|
||||||
|
'3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB',
|
||||||
|
InvoiceID:
|
||||||
|
'6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B',
|
||||||
|
Paths: [
|
||||||
|
[{ currency: 'BTC', issuer: 'r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X' }],
|
||||||
|
],
|
||||||
|
SendMax: '100000000',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field', async function () {
|
||||||
|
const txResult = await testContext.client.autofill(paymentTx)
|
||||||
|
|
||||||
|
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field', async function () {
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
paymentTx.DeliverMax = paymentTx.Amount
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
delete paymentTx.Amount
|
||||||
|
const txResult = await testContext.client.autofill(paymentTx)
|
||||||
|
|
||||||
|
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields', async function () {
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
paymentTx.DeliverMax = paymentTx.Amount
|
||||||
|
|
||||||
|
const txResult = await testContext.client.autofill(paymentTx)
|
||||||
|
|
||||||
|
assert.strictEqual(txResult.Amount, AMOUNT)
|
||||||
|
assert.strictEqual('DeliverMax' in txResult, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Validate Payment transaction API v2: Payment Transaction: differing DeliverMax and Amount fields', async function () {
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
paymentTx.DeliverMax = '6789'
|
||||||
|
paymentTx.Amount = '1234'
|
||||||
|
|
||||||
|
await assertRejects(testContext.client.autofill(paymentTx), ValidationError)
|
||||||
|
})
|
||||||
|
|
||||||
it('should not autofill if fields are present', async function () {
|
it('should not autofill if fields are present', async function () {
|
||||||
const tx: Transaction = {
|
const tx: Transaction = {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Payment } from '../../../src'
|
import { assert } from 'chai'
|
||||||
|
|
||||||
|
import { Payment, Wallet } from '../../../src'
|
||||||
import serverUrl from '../serverUrl'
|
import serverUrl from '../serverUrl'
|
||||||
import {
|
import {
|
||||||
setupClient,
|
setupClient,
|
||||||
@@ -12,24 +14,92 @@ const TIMEOUT = 20000
|
|||||||
|
|
||||||
describe('Payment', function () {
|
describe('Payment', function () {
|
||||||
let testContext: XrplIntegrationTestContext
|
let testContext: XrplIntegrationTestContext
|
||||||
|
let paymentTx: Payment
|
||||||
|
const AMOUNT = '10000000'
|
||||||
|
// This wallet is used for DeliverMax related tests
|
||||||
|
let senderWallet: Wallet
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
testContext = await setupClient(serverUrl)
|
// this payment transaction JSON needs to be refreshed before every test.
|
||||||
|
// Because, we tinker with Amount and DeliverMax fields in the API v2 tests
|
||||||
|
paymentTx = {
|
||||||
|
TransactionType: 'Payment',
|
||||||
|
Account: senderWallet.classicAddress,
|
||||||
|
Amount: AMOUNT,
|
||||||
|
Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy',
|
||||||
|
}
|
||||||
})
|
})
|
||||||
afterEach(async () => teardownClient(testContext))
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
testContext = await setupClient(serverUrl)
|
||||||
|
senderWallet = await generateFundedWallet(testContext.client)
|
||||||
|
})
|
||||||
|
afterAll(async () => teardownClient(testContext))
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'base',
|
'base',
|
||||||
async () => {
|
async () => {
|
||||||
const wallet2 = await generateFundedWallet(testContext.client)
|
|
||||||
const tx: Payment = {
|
const tx: Payment = {
|
||||||
TransactionType: 'Payment',
|
TransactionType: 'Payment',
|
||||||
Account: testContext.wallet.classicAddress,
|
Account: testContext.wallet.classicAddress,
|
||||||
Destination: wallet2.classicAddress,
|
Destination: senderWallet.classicAddress,
|
||||||
Amount: '1000',
|
Amount: '1000',
|
||||||
}
|
}
|
||||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||||
},
|
},
|
||||||
TIMEOUT,
|
TIMEOUT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Validate Payment transaction API v2: Payment Transaction: Specify Only Amount field',
|
||||||
|
async () => {
|
||||||
|
const result = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
paymentTx,
|
||||||
|
senderWallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(result.result.engine_result_code, 0)
|
||||||
|
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Validate Payment transaction API v2: Payment Transaction: Specify Only DeliverMax field',
|
||||||
|
async () => {
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
paymentTx.DeliverMax = paymentTx.Amount
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
delete paymentTx.Amount
|
||||||
|
|
||||||
|
const result = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
paymentTx,
|
||||||
|
senderWallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(result.result.engine_result_code, 0)
|
||||||
|
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'Validate Payment transaction API v2: Payment Transaction: identical DeliverMax and Amount fields',
|
||||||
|
async () => {
|
||||||
|
// @ts-expect-error -- DeliverMax is a non-protocol, RPC level field in Payment transactions
|
||||||
|
paymentTx.DeliverMax = paymentTx.Amount
|
||||||
|
|
||||||
|
const result = await testTransaction(
|
||||||
|
testContext.client,
|
||||||
|
paymentTx,
|
||||||
|
senderWallet,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.equal(result.result.engine_result_code, 0)
|
||||||
|
assert.equal((result.result.tx_json as Payment).Amount, AMOUNT)
|
||||||
|
},
|
||||||
|
TIMEOUT,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user