Skip to content

Commit

Permalink
Fix API decimals handling (#3378)
Browse files Browse the repository at this point in the history
* decimals truncation

* return errors on improper decimals
  • Loading branch information
Defi-Moses authored Nov 7, 2024
1 parent e4e3069 commit 9c294d5
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 5 deletions.
18 changes: 16 additions & 2 deletions packages/rest-api/src/routes/bridgeRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain'
import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'
import { validateRouteExists } from '../validations/validateRouteExists'

import { validateDecimals } from '../validations/validateDecimals'
import { tokenAddressToToken } from '../utils/tokenAddressToToken'
const router: express.Router = express.Router()

/**
Expand Down Expand Up @@ -227,7 +228,20 @@ router.get(
isTokenSupportedOnChain(value, req.query.toChain as string)
)
.withMessage('Token not supported on specified chain'),
check('amount').isNumeric().exists().withMessage('amount is required'),
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.fromChain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
check()
.custom((_value, { req }) => {
const { fromChain, toChain, fromToken, toToken } = req.query
Expand Down
17 changes: 16 additions & 1 deletion packages/rest-api/src/routes/bridgeTxInfoRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain'
import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'
import { validateRouteExists } from '../validations/validateRouteExists'
import { validateDecimals } from '../validations/validateDecimals'
import { tokenAddressToToken } from '../utils/tokenAddressToToken'

const router: express.Router = express.Router()

Expand Down Expand Up @@ -162,7 +164,20 @@ router.get(
isTokenSupportedOnChain(value, req.query.toChain as string)
)
.withMessage('Token not supported on specified chain'),
check('amount').exists().withMessage('amount is required').isNumeric(),
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.fromChain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
check('destAddress')
.exists()
.withMessage('destAddress is required')
Expand Down
17 changes: 16 additions & 1 deletion packages/rest-api/src/routes/swapRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'
import { validSwapTokens } from '../validations/validSwapTokens'
import { validSwapChain } from '../validations/validSwapChain'
import { validateDecimals } from '../validations/validateDecimals'
import { tokenAddressToToken } from '../utils/tokenAddressToToken'

const router: express.Router = express.Router()

Expand Down Expand Up @@ -161,7 +163,20 @@ router.get(
isTokenSupportedOnChain(value, req.query.chain as string)
)
.withMessage('Token not supported on specified chain'),
check('amount').exists().withMessage('amount is required').isNumeric(),
check('amount')
.exists()
.withMessage('amount is required')
.isNumeric()
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.chain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
check()
.custom((_value, { req }) => {
const { chain } = req.query
Expand Down
17 changes: 16 additions & 1 deletion packages/rest-api/src/routes/swapTxInfoRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { isTokenAddress } from '../utils/isTokenAddress'
import { isTokenSupportedOnChain } from '../utils/isTokenSupportedOnChain'
import { checksumAddresses } from '../middleware/checksumAddresses'
import { normalizeNativeTokenAddress } from '../middleware/normalizeNativeTokenAddress'
import { validateDecimals } from '../validations/validateDecimals'
import { tokenAddressToToken } from '../utils/tokenAddressToToken'

const router: express.Router = express.Router()

Expand Down Expand Up @@ -141,7 +143,20 @@ router.get(
isTokenSupportedOnChain(value, req.query.chain as string)
)
.withMessage('Token not supported on specified chain'),
check('amount').isNumeric().exists().withMessage('amount is required'),
check('amount')
.isNumeric()
.exists()
.withMessage('amount is required')
.custom((value, { req }) => {
const fromTokenInfo = tokenAddressToToken(
req.query.chain,
req.query.fromToken
)
return validateDecimals(value, fromTokenInfo.decimals)
})
.withMessage(
'Amount has too many decimals, beyond the maximum allowed for this token'
),
check('address')
.exists()
.withMessage('address is required')
Expand Down
16 changes: 16 additions & 0 deletions packages/rest-api/src/tests/bridgeRoute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,20 @@ describe('Bridge Route with Real Synapse Service', () => {
expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty('field', 'amount')
})

it('should return 400 for amount with too many decimals', async () => {
const response = await request(app).get('/bridge').query({
fromChain: '1',
toChain: '10',
fromToken: USDC.addresses[1],
toToken: USDC.addresses[10],
amount: '1000.123456789', // Assuming USDC has 6 decimals
})

expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty(
'message',
expect.stringContaining('Amount has too many decimals')
)
}, 15000)
})
17 changes: 17 additions & 0 deletions packages/rest-api/src/tests/bridgeTxInfoRoute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,21 @@ describe('Bridge TX Info Route', () => {
'Invalid destination address'
)
})

it('should return 400 for amount with too many decimals', async () => {
const response = await request(app).get('/bridgeTxInfo').query({
fromChain: '1',
toChain: '137',
fromToken: USDC.addresses[1],
toToken: USDC.addresses[137],
amount: '1000.123456789', // Assuming USDC has 6 decimals
destAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
})

expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty(
'message',
expect.stringContaining('Amount has too many decimals')
)
}, 10000)
})
15 changes: 15 additions & 0 deletions packages/rest-api/src/tests/swapRoute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,19 @@ describe('Swap Route with Real Synapse Service', () => {
expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty('field', 'amount')
}, 10_000)

it('should return 400 for amount with too many decimals', async () => {
const response = await request(app).get('/swap').query({
chain: '1',
fromToken: USDC.addresses[1],
toToken: DAI.addresses[1],
amount: '1000.123456789', // Assuming USDC has 6 decimals
})

expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty(
'message',
expect.stringContaining('Amount has too many decimals')
)
}, 10000)
})
16 changes: 16 additions & 0 deletions packages/rest-api/src/tests/swapTxInfoRoute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,20 @@ describe('Swap TX Info Route with Real Synapse Service', () => {
expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty('field', 'amount')
}, 10_000)

it('should return 400 for amount with too many decimals', async () => {
const response = await request(app).get('/swapTxInfo').query({
chain: '1',
fromToken: USDC.addresses[1],
toToken: DAI.addresses[1],
amount: '1000.123456789', // Assuming USDC has 6 decimals
address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
})

expect(response.status).toBe(400)
expect(response.body.error).toHaveProperty(
'message',
expect.stringContaining('Amount has too many decimals')
)
}, 10000)
})
11 changes: 11 additions & 0 deletions packages/rest-api/src/validations/validateDecimals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const validateDecimals = (
amount: string,
expectedDecimals: number
): boolean => {
const parts = amount.split('.')
if (parts.length === 2) {
const decimals = parts[1].length
return decimals <= expectedDecimals
}
return true
}

0 comments on commit 9c294d5

Please sign in to comment.