Skip to content

Commit

Permalink
fix: check token price array & add number validation
Browse files Browse the repository at this point in the history
  • Loading branch information
odcey committed Aug 27, 2024
1 parent 3b73d4d commit e00910d
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 12 deletions.
5 changes: 2 additions & 3 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Squid } from "./index";
import { isValidNumber } from "./utils/numbers";

let squid: Squid;
const testIntegratorId = "test-api";
Expand Down Expand Up @@ -53,9 +54,7 @@ describe("Squid", () => {
chainId: "1",
});

expect(tokensWithPrice.every(tokenPrice => typeof tokenPrice.usdPrice === "number")).toBe(
true,
);
expect(tokensWithPrice.every(tokenPrice => isValidNumber(tokenPrice.usdPrice))).toBe(true);
});
});

Expand Down
29 changes: 20 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
/* eslint-disable no-case-declarations */
import {
ChainType,
CosmosAddress,
CosmosBalance,
EvmWallet,
RouteRequest,
RouteResponse,
SquidData,
StatusResponse,
EvmWallet,
Token,
TokenBalance,
CosmosAddress,
CosmosBalance,
SquidData,
} from "./types";

import HttpAdapter from "./adapter/HttpAdapter";
import { Config, GetStatus, ExecuteRoute, TransactionResponses } from "./types";
import { Config, ExecuteRoute, GetStatus, TransactionResponses } from "./types";

import { CosmosHandler, EvmHandler } from "./handlers";
import { TokensChains } from "./utils/TokensChains";
import { EvmHandler, CosmosHandler } from "./handlers";

import { getChainRpcUrls, getEvmTokensForChainIds } from "./utils/evm";
import { getCosmosChainsForChainIds } from "./utils/cosmos";
import { getChainRpcUrls, getEvmTokensForChainIds } from "./utils/evm";
import { isValidNumber } from "./utils/numbers";

const baseUrl = "https://testnet.api.squidrouter.com/";

Expand Down Expand Up @@ -221,7 +222,17 @@ export class Squid extends TokensChains {
params: { address: tokenAddress, chainId, usdPrice: true },
});

return response.data.token.usdPrice;
const token = response.data.tokens.find(
(t: Token) => t.address.toLowerCase() === tokenAddress.toLowerCase(),
);

if (!token || !isValidNumber(token.usdPrice)) {
throw new Error(
`Valid token price not found for address ${tokenAddress} on chain ${chainId}`,
);
}

return Number(token.usdPrice);
}

/**
Expand All @@ -239,7 +250,7 @@ export class Squid extends TokensChains {
},
});

return response.data.tokens;
return response.data.tokens.filter((token: Token) => isValidNumber(token.usdPrice));
}

public async getFromAmount({
Expand Down
43 changes: 43 additions & 0 deletions src/utils/numbers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ... existing imports ...

import { isValidNumber } from "./numbers";

describe("isValidNumber", () => {
it("should return true for valid numbers", () => {
expect(isValidNumber(0)).toBe(true);
expect(isValidNumber(1)).toBe(true);
expect(isValidNumber(1.5)).toBe(true);
expect(isValidNumber("0")).toBe(true);
expect(isValidNumber("1")).toBe(true);
expect(isValidNumber("1.5")).toBe(true);
expect(isValidNumber("0x0")).toBe(true);
expect(isValidNumber("0x1")).toBe(true);
expect(isValidNumber("0xF")).toBe(true);
expect(isValidNumber("0x1A")).toBe(true);
});

it("should return false for invalid numbers", () => {
expect(isValidNumber(-1)).toBe(false);
expect(isValidNumber("-1")).toBe(false);
expect(isValidNumber("abc")).toBe(false);
expect(isValidNumber("")).toBe(false);
expect(isValidNumber(null)).toBe(false);
expect(isValidNumber(undefined)).toBe(false);
expect(isValidNumber(NaN)).toBe(false);
expect(isValidNumber(Infinity)).toBe(false);
expect(isValidNumber({})).toBe(false);
});

it("should handle large numbers correctly", () => {
expect(isValidNumber(Number.MAX_SAFE_INTEGER)).toBe(true);
expect(isValidNumber(Number.MAX_SAFE_INTEGER.toString())).toBe(true);
expect(isValidNumber("0x" + Number.MAX_SAFE_INTEGER.toString(16))).toBe(true);
});

it("should handle edge cases", () => {
expect(isValidNumber("0x0")).toBe(true);
expect(isValidNumber("0x00")).toBe(true);
expect(isValidNumber("0x")).toBe(false);
expect(isValidNumber("0xG")).toBe(false);
});
});
26 changes: 26 additions & 0 deletions src/utils/numbers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { getNumber, isHexString } from "ethers";

/**
* Checks if a value is a valid number.
* Handles both numeric and string inputs, including hex strings.
*
* @param {any} value - The value to check.
* @returns {boolean} True if the value is a valid, non-negative, finite number; false otherwise.
*/
export const isValidNumber = (value: any): boolean => {
try {
if (value === null || value === undefined || value === "") {
return false;
}

// Handle hex strings
if (typeof value === "string" && isHexString(value)) {
value = getNumber(value);
}

const num = Number(value);
return !isNaN(num) && isFinite(num) && num >= 0;
} catch {
return false;
}
};

0 comments on commit e00910d

Please sign in to comment.