Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
kien-ngo committed Nov 19, 2024
1 parent e0eea33 commit a613e2e
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/stupid-buses-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"thirdweb": minor
---

Add 2 new Pay functions: convertFiatToCrypto and convertCryptoToFiat
10 changes: 10 additions & 0 deletions packages/thirdweb/src/exports/pay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,13 @@ export type {
PayTokenInfo,
PayOnChainTransactionDetails,
} from "../pay/utils/commonTypes.js";

export {
convertFiatToCrypto,
type ConvertFiatToCryptoParams,
} from "../pay/convert/fiatToCrypto.js";

export {
convertCryptoToFiat,
type ConvertCryptoToFiatParams,
} from "../pay/convert/cryptoToFiat.js";
39 changes: 39 additions & 0 deletions packages/thirdweb/src/pay/convert/cryptoToFiat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import { TEST_CLIENT } from "~test/test-clients.js";
import { base } from "../../chains/chain-definitions/base.js";
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
import { convertCryptoToFiat } from "./cryptoToFiat.js";

describe.runIf(process.env.TW_SECRET_KEY)("Pay: fiatToCrypto", () => {
it("should convert ETH price to USD on Ethereum mainnet", async () => {
const result = await convertCryptoToFiat({
chainId: 1,
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
fromAmount: 2,
to: "usd",
client: TEST_CLIENT,
});
expect(result).toBeDefined();
// Should be a number
expect(!Number.isNaN(Number(result))).toBe(true);
// Since eth is around US$3000, we can add a test to check if the price is greater than $1500 (as a safe margin)
// let's hope that scenario does not happen :(
expect(Number(result) > 1500).toBe(true);
});

it("should convert ETH price to USD on Base mainnet", async () => {
const result = await convertCryptoToFiat({
chainId: 1,
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
fromAmount: base.id,
to: "usd",
client: TEST_CLIENT,
});
expect(result).toBeDefined();
// Should be a number
expect(!Number.isNaN(Number(result))).toBe(true);
// Since eth is around US$3000, we can add a test to check if the price is greater than $1500 (as a safe margin)
// let's hope that scenario does not happen :(
expect(Number(result) > 1500).toBe(true);
});
});
47 changes: 47 additions & 0 deletions packages/thirdweb/src/pay/convert/cryptoToFiat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { Address } from "abitype";
import type { ThirdwebClient } from "../../client/client.js";
import { getClientFetch } from "../../utils/fetch.js";
import { getPayConvertCryptoToFiatEndpoint } from "../utils/definitions.js";

export type ConvertCryptoToFiatParams = {
client: ThirdwebClient;
/**
* The contract address of the token
* For native token, use NATIVE_TOKEN_ADDRESS
*/
fromTokenAddress: Address;
fromAmount: number;
/**
* The chainId that the token is deployed to
*/
chainId: number;
/**
* The fiat symbol. e.g "usd"
*/
to: string;
};

export async function convertCryptoToFiat(options: ConvertCryptoToFiatParams) {
const { client, fromTokenAddress, to, chainId, fromAmount } = options;
try {
const queryString = new URLSearchParams({
fromTokenAddress,
to,
chainId: String(chainId),
fromAmount: String(fromAmount),
}).toString();
const url = `${getPayConvertCryptoToFiatEndpoint()}?${queryString}`;
const response = await getClientFetch(client)(url);
// Assuming the response directly matches the BuyWithCryptoStatus interface
if (!response.ok) {
response.body?.cancel();
throw new Error(`HTTP error! status: ${response.status}`);
}

const data: string = (await response.json()).result;
return data;
} catch (error) {
console.error("Fetch error:", error);
throw new Error(`Fetch failed: ${error}`);
}
}
40 changes: 40 additions & 0 deletions packages/thirdweb/src/pay/convert/fiatToCrypto.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it } from "vitest";
import { TEST_CLIENT } from "~test/test-clients.js";
import { base } from "../../chains/chain-definitions/base.js";
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
import { convertFiatToCrypto } from "./fiatToCrypto.js";

describe.runIf(process.env.TW_SECRET_KEY)("Pay: fiatToCrypto", () => {
it("should convert fiat price to token on Ethereum mainnet", async () => {
const result = await convertFiatToCrypto({
chainId: 1,
from: "usd",
fromAmount: 1,
to: NATIVE_TOKEN_ADDRESS,
client: TEST_CLIENT,
});
expect(result).toBeDefined();
// Should be a number
expect(!Number.isNaN(Number(result))).toBe(true);
// Since eth is around US$3000, 1 USD should be around 0.0003
// we give it some safe margin so the test won't be flaky
expect(Number(result) < 0.001).toBe(true);
});

it("should convert fiat price to token on Base mainnet", async () => {
const result = await convertFiatToCrypto({
chainId: base.id,
from: "usd",
fromAmount: 1,
to: NATIVE_TOKEN_ADDRESS,
client: TEST_CLIENT,
});

expect(result).toBeDefined();
// Should be a number
expect(!Number.isNaN(Number(result))).toBe(true);
// Since eth is around US$3000, 1 USD should be around 0.0003
// we give it some safe margin so the test won't be flaky
expect(Number(result) < 0.001).toBe(true);
});
});
47 changes: 47 additions & 0 deletions packages/thirdweb/src/pay/convert/fiatToCrypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { Address } from "abitype";
import type { ThirdwebClient } from "../../client/client.js";
import { getClientFetch } from "../../utils/fetch.js";
import { getPayConvertFiatToCryptoEndpoint } from "../utils/definitions.js";

export type ConvertFiatToCryptoParams = {
client: ThirdwebClient;
/**
* The fiat symbol. e.g: "usd"
*/
from: string;
fromAmount: number;
/**
* The token address
* For native token, use NATIVE_TOKEN_ADDRESS
*/
to: Address;
/**
* The chainId that the token is deployed to
*/
chainId: number;
};

export async function convertFiatToCrypto(options: ConvertFiatToCryptoParams) {
const { client, from, to, chainId, fromAmount } = options;
try {
const queryString = new URLSearchParams({
from,
to,
chainId: String(chainId),
fromAmount: String(fromAmount),
}).toString();
const url = `${getPayConvertFiatToCryptoEndpoint()}?${queryString}`;
const response = await getClientFetch(client)(url);
// Assuming the response directly matches the BuyWithCryptoStatus interface
if (!response.ok) {
response.body?.cancel();
throw new Error(`HTTP error! status: ${response.status}`);
}

const data: string = (await response.json()).result;
return data;
} catch (error) {
console.error("Fetch error:", error);
throw new Error(`Fetch failed: ${error}`);
}
}
6 changes: 6 additions & 0 deletions packages/thirdweb/src/pay/utils/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,9 @@ export const getPaySupportedSources = () =>
*/
export const getPayBuyHistoryEndpoint = () =>
`${getPayBaseUrl()}/wallet/history/v1`;

export const getPayConvertFiatToCryptoEndpoint = () =>
`${getPayBaseUrl()}/convert/fiat-to-crypto/v1`;

export const getPayConvertCryptoToFiatEndpoint = () =>
`${getPayBaseUrl()}/convert/crypto-to-fiat/v1`;
2 changes: 1 addition & 1 deletion packages/thirdweb/src/utils/domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type DomainOverrides = {
export const DEFAULT_RPC_URL = "rpc.thirdweb.com";
const DEFAULT_SOCIAL_URL = "social.thirdweb.com";
const DEFAULT_IN_APP_WALLET_URL = "embedded-wallet.thirdweb.com";
const DEFAULT_PAY_URL = "pay.thirdweb.com";
const DEFAULT_PAY_URL = "localhost:3008"; // "pay.thirdweb.com";
const DEFAULT_STORAGE_URL = "storage.thirdweb.com";
const DEFAULT_BUNDLER_URL = "bundler.thirdweb.com";
const DEFAULT_ANALYTICS_URL = "c.thirdweb.com";
Expand Down

0 comments on commit a613e2e

Please sign in to comment.