test: add AMM integration tests (#2471)

This commit is contained in:
Omar Khan
2023-11-03 18:23:27 -04:00
committed by GitHub
parent 14f40f1f62
commit b47bb39682
13 changed files with 1042 additions and 6 deletions

View File

@@ -163,6 +163,7 @@ XRPFees
# 1.11.0 Amendments
ExpandedSignerList
# 1.12.0 Amendments
AMM
Clawback
fixReducedOffersV1
fixNFTokenRemint

View File

@@ -3,15 +3,15 @@
name: Node.js CI
env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4
on:
push:
branches: [main, 1.x]
pull_request:
workflow_dispatch:
env:
RIPPLED_DOCKER_IMAGE: rippleci/rippled:2.0.0-b4
jobs:
build-and-lint:
runs-on: ubuntu-latest

View File

@@ -64,7 +64,7 @@ From the top-level xrpl.js folder (one level above `packages`), run the followin
```bash
npm install
# sets up the rippled standalone Docker container - you can skip this step if you already have it set up
docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/opt/ripple/etc/ --platform linux/amd64 rippleci/rippled:2.0.0-b3 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg
docker run -p 6006:6006 --interactive -t --volume $PWD/.ci-config:/opt/ripple/etc/ --platform linux/amd64 rippleci/rippled:2.0.0-b4 /opt/ripple/bin/rippled -a --conf /opt/ripple/etc/rippled.cfg
npm run build
npm run test:integration
```

View File

@@ -4,6 +4,7 @@ const base = require('../../jest.config.base.js')
module.exports = {
...base,
roots: [...base.roots, '<rootDir>/test'],
testTimeout: 20000,
testMatch: [
'<rootDir>/test/integration/**/*.test.ts',
'<rootDir>/test/integration/*.test.ts',

View File

@@ -6,6 +6,11 @@ export * from './transactions/escrowCancel.test'
// Transactions
export * from './transactions/accountSet.test'
export * from './transactions/ammBid.test'
export * from './transactions/ammCreate.test'
export * from './transactions/ammDeposit.test'
export * from './transactions/ammVote.test'
export * from './transactions/ammWithdraw.test'
export * from './transactions/checkCancel.test'
export * from './transactions/checkCash.test'
export * from './transactions/checkCreate.test'
@@ -36,6 +41,7 @@ export * from './requests/accountLines.test'
export * from './requests/accountObjects.test'
export * from './requests/accountOffers.test'
export * from './requests/accountTx.test'
export * from './requests/ammInfo.test'
export * from './requests/bookOffers.test'
export * from './requests/channelVerify.test'
export * from './requests/depositAuthorized.test'

View File

@@ -0,0 +1,46 @@
import { assert } from 'chai'
import { isValidClassicAddress } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupAMMPool,
setupClient,
teardownClient,
type TestAMMPool,
type XrplIntegrationTestContext,
} from '../setup'
describe('AMMInfo', function () {
let testContext: XrplIntegrationTestContext
let ammPool: TestAMMPool
beforeAll(async () => {
testContext = await setupClient(serverUrl)
ammPool = await setupAMMPool(testContext.client)
})
afterAll(async () => teardownClient(testContext))
it('base', async function () {
const { asset, asset2 } = ammPool
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
assert.ok(asset2.issuer)
assert.isTrue(isValidClassicAddress(amm.account))
assert.equal(amm.amount, '1250')
assert.deepEqual(amm.amount2, {
currency: asset2.currency,
// @ts-expect-error: asset2.issuer should be defined at this point
issuer: asset2.issuer,
value: '250',
})
assert.equal(amm.trading_fee, 12)
})
})

View File

@@ -1,7 +1,10 @@
import { assert } from 'chai'
import {
AMMDeposit,
AMMDepositFlags,
Client,
Currency,
SignerListSet,
Wallet,
XChainBridge,
@@ -11,11 +14,20 @@ import {
import serverUrl from './serverUrl'
import {
GENESIS_ACCOUNT,
createAMMPool,
fundAccount,
generateFundedWallet,
testTransaction,
} from './utils'
export interface TestAMMPool {
issuerWallet: Wallet
lpWallet: Wallet
testWallet: Wallet
asset: Currency
asset2: Currency
}
interface TestBridge {
xchainBridge: XChainBridge
witness: Wallet
@@ -66,6 +78,33 @@ export async function setupClient(
})
}
export async function setupAMMPool(client: Client): Promise<TestAMMPool> {
const testAMMPool = await createAMMPool(client)
const { issuerWallet, lpWallet, asset, asset2 } = testAMMPool
const testWallet = await generateFundedWallet(client)
// Need to deposit (be an LP) to make bid/vote/withdraw eligible in tests for testContext.wallet
const ammDepositTx: AMMDeposit = {
TransactionType: 'AMMDeposit',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '1000',
Flags: AMMDepositFlags.tfSingleAsset,
}
await testTransaction(client, ammDepositTx, testWallet)
return {
issuerWallet,
lpWallet,
testWallet,
asset,
asset2,
}
}
export async function setupBridge(client: Client): Promise<TestBridge> {
const doorAccount = await generateFundedWallet(client)
const signatureReward = '200'

View File

@@ -0,0 +1,139 @@
import { assert } from 'chai'
import { AMMBid } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupAMMPool,
setupClient,
teardownClient,
type TestAMMPool,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
describe('AMMBid', function () {
let testContext: XrplIntegrationTestContext
let ammPool: TestAMMPool
beforeAll(async () => {
testContext = await setupClient(serverUrl)
ammPool = await setupAMMPool(testContext.client)
})
afterAll(async () => teardownClient(testContext))
it('bid', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const { auction_slot: preAuctionSlot, lp_token: preLPToken } = preAmm
assert.ok(preAuctionSlot)
const ammBidTx: AMMBid = {
TransactionType: 'AMMBid',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
}
await testTransaction(testContext.client, ammBidTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { auction_slot, lp_token } = amm
assert.ok(auction_slot)
// @ts-expect-error: auction_slot should be defined at this point
const afterPriceValue = parseFloat(auction_slot.price.value)
// @ts-expect-error: preAuctionSlot should be defined at this point
const beforePriceValue = parseFloat(preAuctionSlot.price.value)
const diffPriceValue = 0.00268319257224121
const expectedPriceValue = beforePriceValue + diffPriceValue
const afterLPTokenValue = parseFloat(lp_token.value)
const beforeLPTokenValue = parseFloat(preLPToken.value)
const diffLPTokenValue = -0.0026831925721
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterPriceValue, expectedPriceValue)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('vote with AuthAccounts, BidMin, BidMax', async function () {
const { asset, asset2, issuerWallet, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const { auction_slot: preAuctionSlot, lp_token: preLPToken } = preAmm
assert.ok(preAuctionSlot)
const ammBidTx: AMMBid = {
TransactionType: 'AMMBid',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
AuthAccounts: [
{
AuthAccount: {
Account: issuerWallet.classicAddress,
},
},
],
BidMin: { ...preLPToken, value: '5' },
BidMax: { ...preLPToken, value: '10' },
}
await testTransaction(testContext.client, ammBidTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { auction_slot, lp_token } = amm
assert.ok(auction_slot)
// @ts-expect-error: auction_slot should be defined at this point
const afterPriceValue = parseFloat(auction_slot.price.value)
// @ts-expect-error: auction_slot should be defined at this point
const beforePriceValue = parseFloat(preAuctionSlot.price.value)
const diffPriceValue = 4.997316807427759
const expectedPriceValue = beforePriceValue + diffPriceValue
const afterLPTokenValue = parseFloat(lp_token.value)
const beforeLPTokenValue = parseFloat(preLPToken.value)
const diffLPTokenValue = -4.9974509670563
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterPriceValue, expectedPriceValue)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
// @ts-expect-error: auction_slot should be defined at this point
assert.deepEqual(auction_slot.auth_accounts, [
{
account: issuerWallet.classicAddress,
},
])
})
})

View File

@@ -0,0 +1,45 @@
import { assert } from 'chai'
import { isValidClassicAddress } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupClient,
teardownClient,
type XrplIntegrationTestContext,
} from '../setup'
import { createAMMPool } from '../utils'
describe('AMMCreate', function () {
let testContext: XrplIntegrationTestContext
beforeAll(async () => {
testContext = await setupClient(serverUrl)
})
afterAll(async () => teardownClient(testContext))
it('base', async function () {
const ammPool = await createAMMPool(testContext.client)
const { asset, asset2 } = ammPool
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
assert.ok(asset2.issuer)
assert.isTrue(isValidClassicAddress(amm.account))
assert.equal(amm.amount, '250')
assert.deepEqual(amm.amount2, {
currency: asset2.currency,
// @ts-expect-error: asset2.issuer should be defined at this point
issuer: asset2.issuer,
value: '250',
})
assert.equal(amm.trading_fee, 12)
})
})

View File

@@ -0,0 +1,290 @@
/* eslint-disable max-statements -- necessary for readibility */
import { assert } from 'chai'
import { AMMDeposit, AMMDepositFlags } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupAMMPool,
setupClient,
teardownClient,
type TestAMMPool,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
describe('AMMDeposit', function () {
let testContext: XrplIntegrationTestContext
let ammPool: TestAMMPool
beforeAll(async () => {
testContext = await setupClient(serverUrl)
ammPool = await setupAMMPool(testContext.client)
})
afterAll(async () => teardownClient(testContext))
it('deposit with Amount', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const { amount: preAmount, amount2: preAmount2 } = preAmm
const ammDepositTx: AMMDeposit = {
TransactionType: 'AMMDeposit',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '1000',
Flags: AMMDepositFlags.tfSingleAsset,
}
await testTransaction(testContext.client, ammDepositTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = 1000
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
const afterLPToken = lp_token
const beforeLPToken = preAmm.lp_token
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = 191
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.deepEqual(afterAmount2, beforeAmount2)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('deposit with Amount and Amount2', async function () {
const { asset, asset2, issuerWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const { amount: preAmount, amount2: preAmount2 } = preAmm
assert.ok(asset2.issuer)
const ammDepositTx: AMMDeposit = {
TransactionType: 'AMMDeposit',
Account: issuerWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '100',
Amount2: {
currency: asset2.currency,
// @ts-expect-error: asset2.issuer should be defined at this point
issuer: asset2.issuer,
value: '100',
},
Flags: AMMDepositFlags.tfTwoAsset,
}
await testTransaction(testContext.client, ammDepositTx, issuerWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = 100
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
// @ts-expect-error: afterAmount2 should be an object
const afterAmount2Value = parseInt(afterAmount2.value, 10)
// @ts-expect-error: beforeAmount2 should be an object
const beforeAmount2Value = parseInt(beforeAmount2.value, 10)
const diffAmount2Value = 11
const expectedAmount2Value = beforeAmount2Value + diffAmount2Value
const afterLPToken = lp_token
const beforeLPToken = preAmm.lp_token
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = 34
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.equal(afterAmount2Value, expectedAmount2Value)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('deposit with Amount and LPTokenOut', async function () {
const { asset, asset2, issuerWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
const lptokenOut = { ...preLPToken, value: '5' }
const ammDepositTx: AMMDeposit = {
TransactionType: 'AMMDeposit',
Account: issuerWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '100',
LPTokenOut: lptokenOut,
Flags: AMMDepositFlags.tfOneAssetLPToken,
}
await testTransaction(testContext.client, ammDepositTx, issuerWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = 30
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = 5
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.deepEqual(afterAmount2, beforeAmount2)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('deposit with LPTokenOut', async function () {
const { asset, asset2, issuerWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
const lptokenOut = { ...preLPToken, value: '5' }
const ammDepositTx: AMMDeposit = {
TransactionType: 'AMMDeposit',
Account: issuerWallet.classicAddress,
Asset: asset,
Asset2: asset2,
LPTokenOut: lptokenOut,
Flags: AMMDepositFlags.tfLPToken,
}
await testTransaction(testContext.client, ammDepositTx, issuerWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = 15
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
// @ts-expect-error: afterAmount2 should be an object
const afterAmount2Value = parseInt(afterAmount2.value, 10)
// @ts-expect-error: beforeAmount2 should be an object
const beforeAmount2Value = parseInt(beforeAmount2.value, 10)
const diffAmount2Value = 1
const expectedAmount2Value = beforeAmount2Value + diffAmount2Value
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = 5
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.equal(afterAmount2Value, expectedAmount2Value)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
})

View File

@@ -0,0 +1,90 @@
/* eslint-disable max-statements -- necessary for readibility */
import { assert } from 'chai'
import { AMMVote } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupAMMPool,
setupClient,
teardownClient,
type TestAMMPool,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
describe('AMMVote', function () {
let testContext: XrplIntegrationTestContext
let ammPool: TestAMMPool
beforeAll(async () => {
testContext = await setupClient(serverUrl)
ammPool = await setupAMMPool(testContext.client)
})
afterAll(async () => teardownClient(testContext))
it('vote', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
auction_slot: preAuctionSlot,
trading_fee: preTradingFee,
vote_slots: preVoteSlots,
} = preAmm
assert.ok(preAuctionSlot)
assert.ok(preVoteSlots)
// @ts-expect-error: preAuctionSlot should be defined at this point
const { discounted_fee: preDiscountedFee } = preAuctionSlot
const ammVoteTx: AMMVote = {
TransactionType: 'AMMVote',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
TradingFee: 150,
}
await testTransaction(testContext.client, ammVoteTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { auction_slot, trading_fee, vote_slots } = amm
assert.ok(auction_slot)
// @ts-expect-error: auction_slot should be defined at this point
const { discounted_fee } = auction_slot
assert.ok(vote_slots)
const afterTradingFee = trading_fee
const beforeTradingFee = preTradingFee
const diffTradingFee = 76
const expectedTradingFee = beforeTradingFee + diffTradingFee
const afterDiscountedFee = discounted_fee
const beforeDiscountedFee = preDiscountedFee
const diffDiscountedFee = 7
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands -- this is valid
const expectedDiscountedFee = beforeDiscountedFee + diffDiscountedFee
assert.equal(afterTradingFee, expectedTradingFee)
assert.equal(afterDiscountedFee, expectedDiscountedFee)
// @ts-expect-error: preVoteSlots should be defined at this point
assert.equal(vote_slots.length - preVoteSlots.length, 1)
})
})

View File

@@ -0,0 +1,298 @@
/* eslint-disable max-statements -- necessary for readibility */
import { assert } from 'chai'
import { AMMWithdraw, AMMWithdrawFlags } from 'xrpl'
import { AMMInfoResponse } from '../../../src'
import serverUrl from '../serverUrl'
import {
setupAMMPool,
setupClient,
teardownClient,
type TestAMMPool,
type XrplIntegrationTestContext,
} from '../setup'
import { testTransaction } from '../utils'
describe('AMMWithdraw', function () {
let testContext: XrplIntegrationTestContext
let ammPool: TestAMMPool
beforeAll(async () => {
testContext = await setupClient(serverUrl)
ammPool = await setupAMMPool(testContext.client)
})
afterAll(async () => teardownClient(testContext))
it('withdraw with Amount', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
const ammWithdrawTx: AMMWithdraw = {
TransactionType: 'AMMWithdraw',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '500',
Flags: AMMWithdrawFlags.tfSingleAsset,
}
await testTransaction(testContext.client, ammWithdrawTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = -500
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = -126
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.deepEqual(afterAmount2, beforeAmount2)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('withdraw with Amount and Amount2', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
assert.ok(asset2.issuer)
const ammWithdrawTx: AMMWithdraw = {
TransactionType: 'AMMWithdraw',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '50',
Amount2: {
currency: asset2.currency,
// @ts-expect-error: asset2.issuer should be defined at this point
issuer: asset2.issuer,
value: '50',
},
Flags: AMMWithdrawFlags.tfTwoAsset,
}
await testTransaction(testContext.client, ammWithdrawTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = -50
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
// @ts-expect-error: afterAmount2 should be an object
const afterAmount2Value = parseInt(afterAmount2.value, 10)
// @ts-expect-error: beforeAmount2 should be an object
const beforeAmount2Value = parseInt(beforeAmount2.value, 10)
const diffAmount2Value = -17
const expectedAmount2Value = beforeAmount2Value + diffAmount2Value
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = -28
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.equal(afterAmount2Value, expectedAmount2Value)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('withdraw with Amount and LPTokenIn', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
const lptokenIn = { ...preLPToken, value: '5' }
const ammWithdrawTx: AMMWithdraw = {
TransactionType: 'AMMWithdraw',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
Amount: '5',
LPTokenIn: lptokenIn,
Flags: AMMWithdrawFlags.tfOneAssetLPToken,
}
await testTransaction(testContext.client, ammWithdrawTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = -17
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = -5
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.deepEqual(afterAmount2, beforeAmount2)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
it('withdraw with LPTokenIn', async function () {
const { asset, asset2, testWallet } = ammPool
const preAmmInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm: preAmm } = preAmmInfoRes.result
const {
amount: preAmount,
amount2: preAmount2,
lp_token: preLPToken,
} = preAmm
const lptokenIn = { ...preLPToken, value: '5' }
const ammWithdrawTx: AMMWithdraw = {
TransactionType: 'AMMWithdraw',
Account: testWallet.classicAddress,
Asset: asset,
Asset2: asset2,
LPTokenIn: lptokenIn,
Flags: AMMWithdrawFlags.tfLPToken,
}
await testTransaction(testContext.client, ammWithdrawTx, testWallet)
const ammInfoRes: AMMInfoResponse = await testContext.client.request({
command: 'amm_info',
asset,
asset2,
})
const { amm } = ammInfoRes.result
const { amount, amount2, lp_token } = amm
expect(typeof amount).toBe('string')
expect(typeof preAmount).toBe('string')
expect(typeof amount2).toBe('object')
expect(typeof preAmount2).toBe('object')
// @ts-expect-error: amount should be a string
const afterAmountDrops = parseInt(amount, 10)
// @ts-expect-error: preAmount should be a string
const beforeAmountDrops = parseInt(preAmount, 10)
const diffAmountDrops = -9
const expectedAmountDrops = beforeAmountDrops + diffAmountDrops
const afterAmount2 = amount2
const beforeAmount2 = preAmount2
// @ts-expect-error: afterAmount2 should be an object
const afterAmount2Value = parseInt(afterAmount2.value, 10)
// @ts-expect-error: beforeAmount2 should be an object
const beforeAmount2Value = parseInt(beforeAmount2.value, 10)
const diffAmount2Value = -3
const expectedAmount2Value = beforeAmount2Value + diffAmount2Value
const afterLPToken = lp_token
const beforeLPToken = preLPToken
const afterLPTokenValue = parseInt(afterLPToken.value, 10)
const beforeLPTokenValue = parseInt(beforeLPToken.value, 10)
const diffLPTokenValue = -5
const expectedLPTokenValue = beforeLPTokenValue + diffLPTokenValue
assert.equal(afterAmountDrops, expectedAmountDrops)
assert.equal(afterAmount2Value, expectedAmount2Value)
assert.equal(afterLPTokenValue, expectedLPTokenValue)
})
})

View File

@@ -12,8 +12,17 @@ import {
NotConnectedError,
AccountLinesRequest,
IssuedCurrency,
Currency,
} from '../../src'
import { Payment, Transaction } from '../../src/models/transactions'
import {
AMMCreate,
AccountSet,
AccountSetAsfFlags,
Payment,
Transaction,
TrustSet,
TrustSetFlags,
} from '../../src/models/transactions'
import { hashSignedTx } from '../../src/utils/hashes'
export const GENESIS_ACCOUNT = 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'
@@ -192,13 +201,13 @@ export async function verifySubmittedTransaction(
assert(data.result)
assert.deepEqual(
omit(data.result, [
'ctid',
'date',
'hash',
'inLedger',
'ledger_index',
'meta',
'validated',
'ctid',
]),
decodedTx,
)
@@ -360,3 +369,75 @@ export async function getIOUBalance(
}
return (await client.request(request)).result.lines[0].balance
}
export async function createAMMPool(client: Client): Promise<{
issuerWallet: Wallet
lpWallet: Wallet
asset: Currency
asset2: Currency
}> {
const lpWallet = await generateFundedWallet(client)
const issuerWallet = await generateFundedWallet(client)
const currencyCode = 'USD'
const accountSetTx: AccountSet = {
TransactionType: 'AccountSet',
Account: issuerWallet.classicAddress,
SetFlag: AccountSetAsfFlags.asfDefaultRipple,
}
await testTransaction(client, accountSetTx, issuerWallet)
const trustSetTx: TrustSet = {
TransactionType: 'TrustSet',
Flags: TrustSetFlags.tfClearNoRipple,
Account: lpWallet.classicAddress,
LimitAmount: {
currency: currencyCode,
issuer: issuerWallet.classicAddress,
value: '1000',
},
}
await testTransaction(client, trustSetTx, lpWallet)
const paymentTx: Payment = {
TransactionType: 'Payment',
Account: issuerWallet.classicAddress,
Destination: lpWallet.classicAddress,
Amount: {
currency: currencyCode,
issuer: issuerWallet.classicAddress,
value: '500',
},
}
await testTransaction(client, paymentTx, issuerWallet)
const ammCreateTx: AMMCreate = {
TransactionType: 'AMMCreate',
Account: lpWallet.classicAddress,
Amount: '250',
Amount2: {
currency: currencyCode,
issuer: issuerWallet.classicAddress,
value: '250',
},
TradingFee: 12,
}
await testTransaction(client, ammCreateTx, lpWallet)
const asset: Currency = { currency: 'XRP' }
const asset2: Currency = {
currency: currencyCode,
issuer: issuerWallet.classicAddress,
}
return {
issuerWallet,
lpWallet,
asset,
asset2,
}
}