Skip to content

Commit

Permalink
fix: Display AMM Account properly after lsfAMM became AMMID (#808)
Browse files Browse the repository at this point in the history
Updates the view for AMM Accounts to properly display the AMM view
instead of the normal account view.

### Context of Change

`lsfAMM` was removed, but `AMMID` is now returned when doing an
`account_info` request. Also refactors the logic to look up the AMM
object based on the new AMM changes to use `AMMID` instead of looking up
the originating `AMMCreate` transaction.
  • Loading branch information
JST5000 authored Sep 5, 2023
1 parent 9a3483b commit 0a9250f
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 85 deletions.
96 changes: 43 additions & 53 deletions src/containers/Accounts/AMM/AMMAccounts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { useLanguage } from '../../../shared/hooks'
import '../../styles.scss'
import { formatAmount } from '../../../../rippled/lib/txSummary/formatAmount'
import {
getAccountTransactions,
getAccountInfo,
getAMMInfo,
getLedgerEntry,
} from '../../../../rippled/lib/rippled'
import { Tabs } from '../../../shared/components/Tabs'
import { useAnalytics } from '../../../shared/analytics'
Expand All @@ -26,14 +27,6 @@ import { ACCOUNT_ROUTE } from '../../../App/routes'
const getErrorMessage = (error: string) =>
ERROR_MESSAGES[error] || ERROR_MESSAGES.default

function findAMMCreate(txs: [any]) {
const ammCreate = txs.filter((tx) => tx.tx.TransactionType === 'AMMCreate')

if (ammCreate.length < 1) throw new Error('Could not find AMM Create')

return ammCreate[0].tx
}

function renderError(error: any) {
const message = getErrorMessage(error.code)
return (
Expand Down Expand Up @@ -70,50 +63,47 @@ export const AMMAccounts = () => {
Get the first account transaction which in this case should be AMMCreate. From this we get
the two assets in the asset pool.
*/
return (
getAccountTransactions(rippledSocket, accountId, 1, undefined, true)
.then((tData) => {
const tx = findAMMCreate(tData.transactions)
asset1 = formatAsset(tx.Amount)
asset2 = formatAsset(tx.Amount2)

// if one of the assets is XRP, make sure it's the second one
if (asset1.currency === 'XRP') {
const temp = asset2
asset2 = asset1
asset1 = temp
}

return getAMMInfo(rippledSocket, asset1, asset2)
})

/*
Use the assets to get the AMM Info.
*/
.then((ammDataWrapper) => {
ammData = ammDataWrapper.amm
const balance = formatAmount(ammData.amount)
const balance2 = formatAmount(ammData.amount2)

const ammInfo: AmmDataType = {
balance,
balance2,
tradingFee: ammData.trading_fee,
lpBalance: ammData.lp_token.value,
accountId,
language,
}

return ammInfo
})
.catch((e) => {
trackException(
`Error setting up amm account --- ${JSON.stringify(e)}`,
)

throw e
})
)
return getAccountInfo(rippledSocket, accountId)
.then((accountInfo) =>
getLedgerEntry(rippledSocket, { index: accountInfo.AMMID })
.then((ammLedgerEntry) => {
asset1 = formatAsset(ammLedgerEntry.node.Asset)
asset2 = formatAsset(ammLedgerEntry.node.Asset2)

// if one of the assets is XRP, make sure it's the second one
if (asset1.currency === 'XRP') {
const temp = asset2
asset2 = asset1
asset1 = temp
}

return getAMMInfo(rippledSocket, asset1, asset2)
})
/*
Use the assets to get the AMM Info.
*/
.then((ammDataWrapper) => {
ammData = ammDataWrapper.amm
const balance = formatAmount(ammData.amount)
const balance2 = formatAmount(ammData.amount2)

const ammInfo: AmmDataType = {
balance,
balance2,
tradingFee: ammData.trading_fee,
lpBalance: ammData.lp_token.value,
accountId,
language,
}

return ammInfo
}),
)
.catch((e) => {
trackException(`Error setting up amm account --- ${JSON.stringify(e)}`)

throw e
})
})

useEffect(
Expand Down
147 changes: 124 additions & 23 deletions src/containers/Accounts/AMM/AMMAccounts/test/AMMAccounts.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ import { AMMAccounts } from '../index'
import { flushPromises, QuickHarness } from '../../../../test/utils'
import { ACCOUNT_ROUTE } from '../../../../App/routes'

function setSpy(accountTransactions: any, ammInfo: any) {
function setSpy(accountInfo: any, getLedgerEntry: any, ammInfo: any) {
const spyAccountInfo = jest.spyOn(rippled, 'getAccountInfo')
const spyLedgerEntry = jest.spyOn(rippled, 'getLedgerEntry')
const spyInfo = jest.spyOn(rippled, 'getAMMInfo')
const spyTransactions = jest.spyOn(rippled, 'getAccountTransactions')
spyTransactions.mockReturnValue(
spyAccountInfo.mockReturnValue(
new Promise((resolve) => {
resolve(accountTransactions)
resolve(accountInfo)
}),
)
spyLedgerEntry.mockReturnValue(
new Promise((resolve) => {
resolve(getLedgerEntry)
}),
)
spyInfo.mockReturnValue(
Expand All @@ -26,27 +32,100 @@ function setSpy(accountTransactions: any, ammInfo: any) {

describe('AMM Account Page', () => {
const TEST_ACCOUNT_ID = 'rTEST_ACCOUNT'
const accountTransactions: any = {
transactions: [
{
tx: {
Amount: '10000000000',
Amount2: { currency: 'USD', amount: '100000', issuer: 'SOLO' },
TransactionType: 'AMMCreate',
const accountInfo: any = {
AMMID: '0017D8D412779284FDA6A63CEBEADD43BC2FEF37181C3C234ADAC9EFBB5FDB53',
Account: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
Balance: '10000000',
Flags: 26214400,
LedgerEntryType: 'AccountRoot',
OwnerCount: 1,
PreviousTxnID:
'2A9F2B8D74CBECFF339BBD5CD9E42468984D3D8AA5D521B9610F31B014629DC2',
PreviousTxnLgrSeq: 58180,
Sequence: 58180,
index: '115CA30FD281E3265AA22F563B4ADE4BD15A6107F1E5105056F191882BE78FC4',
}

const ledgerEntry: any = {
index: '0017D8D412779284FDA6A63CEBEADD43BC2FEF37181C3C234ADAC9EFBB5FDB53',
ledger_hash:
'6C1914FF5966D2FD060B92B07A30A303369F28132DB5E8D73BED4FFC8A372EF2',
ledger_index: 285601,
node: {
Account: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
Asset: {
currency: 'XRP',
},
Asset2: {
currency: 'USD',
issuer: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
},
AuctionSlot: {
Account: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
Expiration: 745719332,
Price: {
currency: '03930D02208264E2E40EC1B0C09E4DB96EE197B1',
issuer: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
value: '0',
},
},
],
Flags: 0,
LPTokenBalance: {
currency: '03930D02208264E2E40EC1B0C09E4DB96EE197B1',
issuer: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
value: '10000',
},
LedgerEntryType: 'AMM',
VoteSlots: [
{
VoteEntry: {
Account: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
VoteWeight: 100000,
},
},
],
index: '0017D8D412779284FDA6A63CEBEADD43BC2FEF37181C3C234ADAC9EFBB5FDB53',
},
validated: true,
}

const ammInfo: any = {
amm: {
amount: '10000000000',
amount2: { currency: 'USD', value: '100000' },
trading_fee: 10,
account: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
amount: '10000000',
amount2: {
currency: 'USD',
issuer: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
value: '10',
},
asset2_frozen: false,
auction_slot: {
account: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
discounted_fee: 0,
expiration: '2023-08-19T00:15:32+0000',
price: {
currency: '03930D02208264E2E40EC1B0C09E4DB96EE197B1',
issuer: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
value: '0',
},
time_interval: 20,
},
lp_token: {
value: '8989',
currency: '03930D02208264E2E40EC1B0C09E4DB96EE197B1',
issuer: 'rJbt6ryq1TzikBuvVQDaxVLqL77eJeibsj',
value: '10000',
},
trading_fee: 0,
vote_slots: [
{
account: 'rJd9Ti4TF2Mrn268LW7sSw8E16J4hYzMiD',
trading_fee: 0,
vote_weight: 100000,
},
],
},
ledger_current_index: 285641,
validated: false,
}

const createWrapper = () =>
Expand All @@ -59,8 +138,8 @@ describe('AMM Account Page', () => {
</QuickHarness>,
)

it('renders AMM account page when TVL not present', async () => {
setSpy(accountTransactions, ammInfo)
it('renders AMM account page', async () => {
setSpy(accountInfo, ledgerEntry, ammInfo)

const wrapper = createWrapper()
await flushPromises()
Expand All @@ -71,7 +150,7 @@ describe('AMM Account Page', () => {
})

it('shows error when amm info data is formatted incorrectly', async () => {
setSpy(accountTransactions, 'ammInfo')
setSpy(accountInfo, ledgerEntry, 'ammInfo')

const wrapper = await createWrapper()
await flushPromises()
Expand All @@ -82,12 +161,34 @@ describe('AMM Account Page', () => {
wrapper.unmount()
})

it('shows error when account transactions data is formatted incorrectly', async () => {
const accTransBad: any = {
transactions: [],
it('shows error when account_info has no AMMID', async () => {
const badAccountInfo: any = {
...accountInfo,
}

delete badAccountInfo.AMMID

const badLedgerEntry = {
error: 'invalidParams',
error_code: 31,
error_message: 'indexMalformed',
status: 'error',
type: 'response',
request: {
command: 'ledger_entry',
index: '',
ledger_index: 'validated',
},
warnings: [
{
id: 2001,
message:
"This is a clio server. clio only serves validated data. If you want to talk to rippled, include 'ledger_index':'current' in your request",
},
],
}

setSpy(accTransBad, ammInfo)
setSpy(badAccountInfo, badLedgerEntry, ammInfo)

const wrapper = createWrapper()
await flushPromises()
Expand Down
8 changes: 2 additions & 6 deletions src/containers/Accounts/AccountsRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import NoMatch from '../NoMatch'
import { Accounts } from './index'
import { ERROR_MESSAGES } from './Errors'
import { Loader } from '../shared/components/Loader'
import { ACCOUNT_FLAGS, Error } from '../../rippled/lib/utils'
import { Error } from '../../rippled/lib/utils'
import { BAD_REQUEST } from '../shared/utils'

const getErrorMessage = (error: any) =>
Expand All @@ -31,10 +31,6 @@ function renderError(error: any) {
export const AccountsRouter = () => {
const { id: accountId = '' } = useParams<{ id: string }>()
const rippledSocket = useContext(SocketContext)
const flags: any = Object.entries(ACCOUNT_FLAGS).reduce(
(all, [key, value]) => ({ ...all, [value]: key }),
{},
)

const { data: comp, error } = useQuery([accountId], () => {
let classicAddress = accountId
Expand All @@ -49,7 +45,7 @@ export const AccountsRouter = () => {
return (
getAccountInfo(rippledSocket, classicAddress)
.then((data: any) => {
if (data.Flags & flags.lsfAMM) {
if (data.AMMID) {
return <AMMAccounts />
}
return <Accounts />
Expand Down
Loading

0 comments on commit 0a9250f

Please sign in to comment.