thirdweb 5.72.0-nightly-8aa454cbbbc2079749fa8250102ab0307d1b33af-20241202003724 → 5.73.0-nightly-ea855c66cb940d1adafefaad6dd689227701d277-20241203000359
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/exports/pay.js +5 -1
- package/dist/cjs/exports/pay.js.map +1 -1
- package/dist/cjs/pay/convert/cryptoToFiat.js +73 -0
- package/dist/cjs/pay/convert/cryptoToFiat.js.map +1 -0
- package/dist/cjs/pay/convert/fiatToCrypto.js +73 -0
- package/dist/cjs/pay/convert/fiatToCrypto.js.map +1 -0
- package/dist/cjs/pay/utils/definitions.js +5 -1
- package/dist/cjs/pay/utils/definitions.js.map +1 -1
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js +2 -33
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js +3 -28
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js.map +1 -1
- package/dist/cjs/transaction/actions/zksync/send-eip712-transaction.js +3 -1
- package/dist/cjs/transaction/actions/zksync/send-eip712-transaction.js.map +1 -1
- package/dist/cjs/transaction/utils.js +27 -0
- package/dist/cjs/transaction/utils.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/exports/pay.js +2 -0
- package/dist/esm/exports/pay.js.map +1 -1
- package/dist/esm/pay/convert/cryptoToFiat.js +70 -0
- package/dist/esm/pay/convert/cryptoToFiat.js.map +1 -0
- package/dist/esm/pay/convert/fiatToCrypto.js +70 -0
- package/dist/esm/pay/convert/fiatToCrypto.js.map +1 -0
- package/dist/esm/pay/utils/definitions.js +2 -0
- package/dist/esm/pay/utils/definitions.js.map +1 -1
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js +2 -33
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js +1 -26
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.js.map +1 -1
- package/dist/esm/transaction/actions/zksync/send-eip712-transaction.js +3 -1
- package/dist/esm/transaction/actions/zksync/send-eip712-transaction.js.map +1 -1
- package/dist/esm/transaction/utils.js +26 -0
- package/dist/esm/transaction/utils.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/types/exports/pay.d.ts +2 -0
- package/dist/types/exports/pay.d.ts.map +1 -1
- package/dist/types/pay/convert/cryptoToFiat.d.ts +54 -0
- package/dist/types/pay/convert/cryptoToFiat.d.ts.map +1 -0
- package/dist/types/pay/convert/fiatToCrypto.d.ts +55 -0
- package/dist/types/pay/convert/fiatToCrypto.d.ts.map +1 -0
- package/dist/types/pay/utils/definitions.d.ts +2 -0
- package/dist/types/pay/utils/definitions.d.ts.map +1 -1
- package/dist/types/react/core/hooks/transaction/useSendTransaction.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.d.ts.map +1 -1
- package/dist/types/transaction/actions/zksync/send-eip712-transaction.d.ts.map +1 -1
- package/dist/types/transaction/utils.d.ts +2 -0
- package/dist/types/transaction/utils.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +19 -19
- package/src/exports/pay.ts +10 -0
- package/src/pay/convert/cryptoToFiat.test.ts +95 -0
- package/src/pay/convert/cryptoToFiat.ts +111 -0
- package/src/pay/convert/fiatToCrypto.test.ts +96 -0
- package/src/pay/convert/fiatToCrypto.ts +110 -0
- package/src/pay/utils/definitions.ts +6 -0
- package/src/react/core/hooks/transaction/useSendTransaction.ts +2 -39
- package/src/react/web/ui/ConnectWallet/screens/Buy/main/useBuyTxStates.ts +1 -29
- package/src/transaction/actions/zksync/send-eip712-transaction.ts +5 -1
- package/src/transaction/utils.ts +33 -0
- package/src/version.ts +1 -1
@@ -0,0 +1,95 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { TEST_CLIENT } from "~test/test-clients.js";
|
3
|
+
import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
|
4
|
+
import { base } from "../../chains/chain-definitions/base.js";
|
5
|
+
import { ethereum } from "../../chains/chain-definitions/ethereum.js";
|
6
|
+
import { sepolia } from "../../chains/chain-definitions/sepolia.js";
|
7
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
|
8
|
+
import { convertCryptoToFiat } from "./cryptoToFiat.js";
|
9
|
+
|
10
|
+
describe.runIf(process.env.TW_SECRET_KEY)("Pay: crypto-to-fiat", () => {
|
11
|
+
it("should convert ETH price to USD on Ethereum mainnet", async () => {
|
12
|
+
const data = await convertCryptoToFiat({
|
13
|
+
chain: ethereum,
|
14
|
+
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
|
15
|
+
fromAmount: 1,
|
16
|
+
to: "USD",
|
17
|
+
client: TEST_CLIENT,
|
18
|
+
});
|
19
|
+
expect(data.result).toBeDefined();
|
20
|
+
// Should be a number
|
21
|
+
expect(!Number.isNaN(data.result)).toBe(true);
|
22
|
+
// Since eth is around US$3000, we can add a test to check if the price is greater than $1500 (as a safe margin)
|
23
|
+
// let's hope that scenario does not happen :(
|
24
|
+
expect(Number(data.result) > 1500).toBe(true);
|
25
|
+
});
|
26
|
+
|
27
|
+
it("should convert ETH price to USD on Base mainnet", async () => {
|
28
|
+
const data = await convertCryptoToFiat({
|
29
|
+
chain: base,
|
30
|
+
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
|
31
|
+
fromAmount: 1,
|
32
|
+
to: "USD",
|
33
|
+
client: TEST_CLIENT,
|
34
|
+
});
|
35
|
+
expect(data.result).toBeDefined();
|
36
|
+
// Should be a number
|
37
|
+
expect(!Number.isNaN(data.result)).toBe(true);
|
38
|
+
// Since eth is around US$3000, we can add a test to check if the price is greater than $1500 (as a safe margin)
|
39
|
+
// let's hope that scenario does not happen :(
|
40
|
+
expect(data.result > 1500).toBe(true);
|
41
|
+
});
|
42
|
+
|
43
|
+
it("should return zero if fromAmount is zero", async () => {
|
44
|
+
const data = await convertCryptoToFiat({
|
45
|
+
chain: base,
|
46
|
+
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
|
47
|
+
fromAmount: 0,
|
48
|
+
to: "USD",
|
49
|
+
client: TEST_CLIENT,
|
50
|
+
});
|
51
|
+
expect(data.result).toBe(0);
|
52
|
+
});
|
53
|
+
|
54
|
+
it("should throw error for testnet chain (because testnets are not supported", async () => {
|
55
|
+
await expect(() =>
|
56
|
+
convertCryptoToFiat({
|
57
|
+
chain: sepolia,
|
58
|
+
fromTokenAddress: NATIVE_TOKEN_ADDRESS,
|
59
|
+
fromAmount: 1,
|
60
|
+
to: "USD",
|
61
|
+
client: TEST_CLIENT,
|
62
|
+
}),
|
63
|
+
).rejects.toThrowError(
|
64
|
+
`Cannot fetch price for a testnet (chainId: ${sepolia.id})`,
|
65
|
+
);
|
66
|
+
});
|
67
|
+
|
68
|
+
it("should throw error if fromTokenAddress is set to an invalid EVM address", async () => {
|
69
|
+
await expect(() =>
|
70
|
+
convertCryptoToFiat({
|
71
|
+
chain: ethereum,
|
72
|
+
fromTokenAddress: "haha",
|
73
|
+
fromAmount: 1,
|
74
|
+
to: "USD",
|
75
|
+
client: TEST_CLIENT,
|
76
|
+
}),
|
77
|
+
).rejects.toThrowError(
|
78
|
+
"Invalid fromTokenAddress. Expected a valid EVM contract address",
|
79
|
+
);
|
80
|
+
});
|
81
|
+
|
82
|
+
it("should throw error if fromTokenAddress is set to a wallet address", async () => {
|
83
|
+
await expect(() =>
|
84
|
+
convertCryptoToFiat({
|
85
|
+
chain: base,
|
86
|
+
fromTokenAddress: TEST_ACCOUNT_A.address,
|
87
|
+
fromAmount: 1,
|
88
|
+
to: "USD",
|
89
|
+
client: TEST_CLIENT,
|
90
|
+
}),
|
91
|
+
).rejects.toThrowError(
|
92
|
+
`Error: ${TEST_ACCOUNT_A.address} on chainId: ${base.id} is not a valid contract address.`,
|
93
|
+
);
|
94
|
+
});
|
95
|
+
});
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import type { Address } from "abitype";
|
2
|
+
import type { Chain } from "../../chains/types.js";
|
3
|
+
import type { ThirdwebClient } from "../../client/client.js";
|
4
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
|
5
|
+
import { getBytecode } from "../../contract/actions/get-bytecode.js";
|
6
|
+
import { getContract } from "../../contract/contract.js";
|
7
|
+
import { isAddress } from "../../utils/address.js";
|
8
|
+
import { getClientFetch } from "../../utils/fetch.js";
|
9
|
+
import { getPayConvertCryptoToFiatEndpoint } from "../utils/definitions.js";
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Props for the `convertCryptoToFiat` function
|
13
|
+
* @buyCrypto
|
14
|
+
*/
|
15
|
+
export type ConvertCryptoToFiatParams = {
|
16
|
+
client: ThirdwebClient;
|
17
|
+
/**
|
18
|
+
* The contract address of the token
|
19
|
+
* For native token, use NATIVE_TOKEN_ADDRESS
|
20
|
+
*/
|
21
|
+
fromTokenAddress: Address;
|
22
|
+
/**
|
23
|
+
* The amount of token to convert to fiat value
|
24
|
+
*/
|
25
|
+
fromAmount: number;
|
26
|
+
/**
|
27
|
+
* The chain that the token is deployed to
|
28
|
+
*/
|
29
|
+
chain: Chain;
|
30
|
+
/**
|
31
|
+
* The fiat symbol. e.g "USD"
|
32
|
+
* Only USD is supported at the moment.
|
33
|
+
*/
|
34
|
+
to: "USD";
|
35
|
+
};
|
36
|
+
|
37
|
+
/**
|
38
|
+
* Get a price of a token (using tokenAddress + chainId) in fiat.
|
39
|
+
* Only USD is supported at the moment.
|
40
|
+
* @example
|
41
|
+
* ### Basic usage
|
42
|
+
* For native token (non-ERC20), you should use NATIVE_TOKEN_ADDRESS as the value for `tokenAddress`
|
43
|
+
* ```ts
|
44
|
+
* import { convertCryptoToFiat } from "thirdweb/pay";
|
45
|
+
*
|
46
|
+
* // Get Ethereum price
|
47
|
+
* const result = convertCryptoToFiat({
|
48
|
+
* fromTokenAddress: NATIVE_TOKEN_ADDRESS,
|
49
|
+
* to: "USD",
|
50
|
+
* chain: ethereum,
|
51
|
+
* fromAmount: 1,
|
52
|
+
* });
|
53
|
+
*
|
54
|
+
* // Result: `{ result: 3404.11 }`
|
55
|
+
* ```
|
56
|
+
* @buyCrypto
|
57
|
+
* @returns a number representing the price (in selected fiat) of "x" token, with "x" being the `fromAmount`.
|
58
|
+
*/
|
59
|
+
export async function convertCryptoToFiat(
|
60
|
+
options: ConvertCryptoToFiatParams,
|
61
|
+
): Promise<{ result: number }> {
|
62
|
+
const { client, fromTokenAddress, to, chain, fromAmount } = options;
|
63
|
+
if (Number(fromAmount) === 0) {
|
64
|
+
return { result: 0 };
|
65
|
+
}
|
66
|
+
// Testnets just don't work with our current provider(s)
|
67
|
+
if (chain.testnet === true) {
|
68
|
+
throw new Error(`Cannot fetch price for a testnet (chainId: ${chain.id})`);
|
69
|
+
}
|
70
|
+
// Some provider that we are using will return `0` for unsupported token
|
71
|
+
// so we should do some basic input validations before sending the request
|
72
|
+
|
73
|
+
// Make sure it's a valid EVM address
|
74
|
+
if (!isAddress(fromTokenAddress)) {
|
75
|
+
throw new Error(
|
76
|
+
"Invalid fromTokenAddress. Expected a valid EVM contract address",
|
77
|
+
);
|
78
|
+
}
|
79
|
+
// Make sure it's either a valid contract or a native token address
|
80
|
+
if (fromTokenAddress.toLowerCase() !== NATIVE_TOKEN_ADDRESS.toLowerCase()) {
|
81
|
+
const bytecode = await getBytecode(
|
82
|
+
getContract({
|
83
|
+
address: fromTokenAddress,
|
84
|
+
chain,
|
85
|
+
client,
|
86
|
+
}),
|
87
|
+
).catch(() => undefined);
|
88
|
+
if (!bytecode || bytecode === "0x") {
|
89
|
+
throw new Error(
|
90
|
+
`Error: ${fromTokenAddress} on chainId: ${chain.id} is not a valid contract address.`,
|
91
|
+
);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
const params = {
|
95
|
+
fromTokenAddress,
|
96
|
+
to,
|
97
|
+
chainId: String(chain.id),
|
98
|
+
fromAmount: String(fromAmount),
|
99
|
+
};
|
100
|
+
const queryString = new URLSearchParams(params).toString();
|
101
|
+
const url = `${getPayConvertCryptoToFiatEndpoint()}?${queryString}`;
|
102
|
+
const response = await getClientFetch(client)(url);
|
103
|
+
if (!response.ok) {
|
104
|
+
throw new Error(
|
105
|
+
`Failed to fetch ${to} value for token (${fromTokenAddress}) on chainId: ${chain.id}`,
|
106
|
+
);
|
107
|
+
}
|
108
|
+
|
109
|
+
const data: { result: number } = await response.json();
|
110
|
+
return data;
|
111
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { TEST_CLIENT } from "~test/test-clients.js";
|
3
|
+
import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
|
4
|
+
import { base } from "../../chains/chain-definitions/base.js";
|
5
|
+
import { ethereum } from "../../chains/chain-definitions/ethereum.js";
|
6
|
+
import { sepolia } from "../../chains/chain-definitions/sepolia.js";
|
7
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
|
8
|
+
import { convertFiatToCrypto } from "./fiatToCrypto.js";
|
9
|
+
|
10
|
+
describe.runIf(process.env.TW_SECRET_KEY)("Pay: fiatToCrypto", () => {
|
11
|
+
it("should convert fiat price to token on Ethereum mainnet", async () => {
|
12
|
+
const data = await convertFiatToCrypto({
|
13
|
+
chain: ethereum,
|
14
|
+
from: "USD",
|
15
|
+
fromAmount: 1,
|
16
|
+
to: NATIVE_TOKEN_ADDRESS,
|
17
|
+
client: TEST_CLIENT,
|
18
|
+
});
|
19
|
+
expect(data.result).toBeDefined();
|
20
|
+
// Should be a number
|
21
|
+
expect(!Number.isNaN(data.result)).toBe(true);
|
22
|
+
// Since eth is around US$3000, 1 USD should be around 0.0003
|
23
|
+
// we give it some safe margin so the test won't be flaky
|
24
|
+
expect(data.result < 0.001).toBe(true);
|
25
|
+
});
|
26
|
+
|
27
|
+
it("should convert fiat price to token on Base mainnet", async () => {
|
28
|
+
const data = await convertFiatToCrypto({
|
29
|
+
chain: base,
|
30
|
+
from: "USD",
|
31
|
+
fromAmount: 1,
|
32
|
+
to: NATIVE_TOKEN_ADDRESS,
|
33
|
+
client: TEST_CLIENT,
|
34
|
+
});
|
35
|
+
|
36
|
+
expect(data.result).toBeDefined();
|
37
|
+
// Should be a number
|
38
|
+
expect(!Number.isNaN(data.result)).toBe(true);
|
39
|
+
// Since eth is around US$3000, 1 USD should be around 0.0003
|
40
|
+
// we give it some safe margin so the test won't be flaky
|
41
|
+
expect(data.result < 0.001).toBe(true);
|
42
|
+
});
|
43
|
+
|
44
|
+
it("should return zero if the fromAmount is zero", async () => {
|
45
|
+
const data = await convertFiatToCrypto({
|
46
|
+
chain: base,
|
47
|
+
from: "USD",
|
48
|
+
fromAmount: 0,
|
49
|
+
to: NATIVE_TOKEN_ADDRESS,
|
50
|
+
client: TEST_CLIENT,
|
51
|
+
});
|
52
|
+
expect(data.result).toBe(0);
|
53
|
+
});
|
54
|
+
|
55
|
+
it("should throw error for testnet chain (because testnets are not supported", async () => {
|
56
|
+
await expect(() =>
|
57
|
+
convertFiatToCrypto({
|
58
|
+
chain: sepolia,
|
59
|
+
to: NATIVE_TOKEN_ADDRESS,
|
60
|
+
fromAmount: 1,
|
61
|
+
from: "USD",
|
62
|
+
client: TEST_CLIENT,
|
63
|
+
}),
|
64
|
+
).rejects.toThrowError(
|
65
|
+
`Cannot fetch price for a testnet (chainId: ${sepolia.id})`,
|
66
|
+
);
|
67
|
+
});
|
68
|
+
|
69
|
+
it("should throw error if `to` is set to an invalid EVM address", async () => {
|
70
|
+
await expect(() =>
|
71
|
+
convertFiatToCrypto({
|
72
|
+
chain: ethereum,
|
73
|
+
to: "haha",
|
74
|
+
fromAmount: 1,
|
75
|
+
from: "USD",
|
76
|
+
client: TEST_CLIENT,
|
77
|
+
}),
|
78
|
+
).rejects.toThrowError(
|
79
|
+
"Invalid `to`. Expected a valid EVM contract address",
|
80
|
+
);
|
81
|
+
});
|
82
|
+
|
83
|
+
it("should throw error if `to` is set to a wallet address", async () => {
|
84
|
+
await expect(() =>
|
85
|
+
convertFiatToCrypto({
|
86
|
+
chain: base,
|
87
|
+
to: TEST_ACCOUNT_A.address,
|
88
|
+
fromAmount: 1,
|
89
|
+
from: "USD",
|
90
|
+
client: TEST_CLIENT,
|
91
|
+
}),
|
92
|
+
).rejects.toThrowError(
|
93
|
+
`Error: ${TEST_ACCOUNT_A.address} on chainId: ${base.id} is not a valid contract address.`,
|
94
|
+
);
|
95
|
+
});
|
96
|
+
});
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import type { Address } from "abitype";
|
2
|
+
import type { Chain } from "../../chains/types.js";
|
3
|
+
import type { ThirdwebClient } from "../../client/client.js";
|
4
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../constants/addresses.js";
|
5
|
+
import { getBytecode } from "../../contract/actions/get-bytecode.js";
|
6
|
+
import { getContract } from "../../contract/contract.js";
|
7
|
+
import { isAddress } from "../../utils/address.js";
|
8
|
+
import { getClientFetch } from "../../utils/fetch.js";
|
9
|
+
import { getPayConvertFiatToCryptoEndpoint } from "../utils/definitions.js";
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Props for the `convertFiatToCrypto` function
|
13
|
+
* @buyCrypto
|
14
|
+
*/
|
15
|
+
export type ConvertFiatToCryptoParams = {
|
16
|
+
client: ThirdwebClient;
|
17
|
+
/**
|
18
|
+
* The fiat symbol. e.g: "USD"
|
19
|
+
* Currently only USD is supported.
|
20
|
+
*/
|
21
|
+
from: "USD";
|
22
|
+
/**
|
23
|
+
* The total amount of fiat to convert
|
24
|
+
* e.g: If you want to convert 2 cents to USD, enter `0.02`
|
25
|
+
*/
|
26
|
+
fromAmount: number;
|
27
|
+
/**
|
28
|
+
* The token address
|
29
|
+
* For native token, use NATIVE_TOKEN_ADDRESS
|
30
|
+
*/
|
31
|
+
to: Address;
|
32
|
+
/**
|
33
|
+
* The chain that the token is deployed to
|
34
|
+
*/
|
35
|
+
chain: Chain;
|
36
|
+
};
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Convert a fiat value to a token.
|
40
|
+
* Currently only USD is supported.
|
41
|
+
* @example
|
42
|
+
* ### Basic usage
|
43
|
+
* ```ts
|
44
|
+
* import { convertFiatToCrypto } from "thirdweb/pay";
|
45
|
+
*
|
46
|
+
* // Convert 2 cents to ETH
|
47
|
+
* const result = await convertFiatToCrypto({
|
48
|
+
* from: "USD",
|
49
|
+
* // the token address. For native token, use NATIVE_TOKEN_ADDRESS
|
50
|
+
* to: "0x...",
|
51
|
+
* // the chain (of the chain where the token belong to)
|
52
|
+
* chain: ethereum,
|
53
|
+
* // 2 cents
|
54
|
+
* fromAmount: 0.02,
|
55
|
+
* });
|
56
|
+
* ```
|
57
|
+
* Result: `{ result: 0.0000057 }`
|
58
|
+
* @buyCrypto
|
59
|
+
*/
|
60
|
+
export async function convertFiatToCrypto(
|
61
|
+
options: ConvertFiatToCryptoParams,
|
62
|
+
): Promise<{ result: number }> {
|
63
|
+
const { client, from, to, chain, fromAmount } = options;
|
64
|
+
if (Number(fromAmount) === 0) {
|
65
|
+
return { result: 0 };
|
66
|
+
}
|
67
|
+
// Testnets just don't work with our current provider(s)
|
68
|
+
if (chain.testnet === true) {
|
69
|
+
throw new Error(`Cannot fetch price for a testnet (chainId: ${chain.id})`);
|
70
|
+
}
|
71
|
+
// Some provider that we are using will return `0` for unsupported token
|
72
|
+
// so we should do some basic input validations before sending the request
|
73
|
+
|
74
|
+
// Make sure it's a valid EVM address
|
75
|
+
if (!isAddress(to)) {
|
76
|
+
throw new Error("Invalid `to`. Expected a valid EVM contract address");
|
77
|
+
}
|
78
|
+
// Make sure it's either a valid contract or a native token
|
79
|
+
if (to.toLowerCase() !== NATIVE_TOKEN_ADDRESS.toLowerCase()) {
|
80
|
+
const bytecode = await getBytecode(
|
81
|
+
getContract({
|
82
|
+
address: to,
|
83
|
+
chain,
|
84
|
+
client,
|
85
|
+
}),
|
86
|
+
).catch(() => undefined);
|
87
|
+
if (!bytecode || bytecode === "0x") {
|
88
|
+
throw new Error(
|
89
|
+
`Error: ${to} on chainId: ${chain.id} is not a valid contract address.`,
|
90
|
+
);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
const params = {
|
94
|
+
from,
|
95
|
+
to,
|
96
|
+
chainId: String(chain.id),
|
97
|
+
fromAmount: String(fromAmount),
|
98
|
+
};
|
99
|
+
const queryString = new URLSearchParams(params).toString();
|
100
|
+
const url = `${getPayConvertFiatToCryptoEndpoint()}?${queryString}`;
|
101
|
+
const response = await getClientFetch(client)(url);
|
102
|
+
if (!response.ok) {
|
103
|
+
throw new Error(
|
104
|
+
`Failed to convert ${to} value to token (${to}) on chainId: ${chain.id}`,
|
105
|
+
);
|
106
|
+
}
|
107
|
+
|
108
|
+
const data: { result: number } = await response.json();
|
109
|
+
return data;
|
110
|
+
}
|
@@ -76,3 +76,9 @@ export const getPaySupportedSources = () =>
|
|
76
76
|
*/
|
77
77
|
export const getPayBuyHistoryEndpoint = () =>
|
78
78
|
`${getPayBaseUrl()}/wallet/history/v1`;
|
79
|
+
|
80
|
+
export const getPayConvertFiatToCryptoEndpoint = () =>
|
81
|
+
`${getPayBaseUrl()}/convert/fiat-to-crypto/v1`;
|
82
|
+
|
83
|
+
export const getPayConvertCryptoToFiatEndpoint = () =>
|
84
|
+
`${getPayBaseUrl()}/convert/crypto-to-fiat/v1`;
|
@@ -1,14 +1,13 @@
|
|
1
1
|
import { type UseMutationResult, useMutation } from "@tanstack/react-query";
|
2
2
|
import type { Chain } from "../../../../chains/types.js";
|
3
|
-
import { getGasPrice } from "../../../../gas/get-gas-price.js";
|
4
3
|
import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
|
5
4
|
import type { BuyWithFiatStatus } from "../../../../pay/buyWithFiat/getStatus.js";
|
6
5
|
import type { FiatProvider } from "../../../../pay/utils/commonTypes.js";
|
7
|
-
import { estimateGasCost } from "../../../../transaction/actions/estimate-gas-cost.js";
|
8
6
|
import type { GaslessOptions } from "../../../../transaction/actions/gasless/types.js";
|
9
7
|
import { sendTransaction } from "../../../../transaction/actions/send-transaction.js";
|
10
8
|
import type { WaitForReceiptOptions } from "../../../../transaction/actions/wait-for-tx-receipt.js";
|
11
9
|
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
|
10
|
+
import { getTransactionGasCost } from "../../../../transaction/utils.js";
|
12
11
|
import { resolvePromisedValue } from "../../../../utils/promise/resolve-promised-value.js";
|
13
12
|
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
|
14
13
|
import { getTokenBalance } from "../../../../wallets/utils/getTokenBalance.js";
|
@@ -215,7 +214,7 @@ export function useSendTransactionCore(args: {
|
|
215
214
|
tokenAddress: _erc20Value.tokenAddress,
|
216
215
|
})
|
217
216
|
: undefined,
|
218
|
-
|
217
|
+
getTransactionGasCost(tx, account.address),
|
219
218
|
]);
|
220
219
|
|
221
220
|
const gasSponsored = hasSponsoredTransactionsEnabled(wallet);
|
@@ -248,39 +247,3 @@ export function useSendTransactionCore(args: {
|
|
248
247
|
},
|
249
248
|
});
|
250
249
|
}
|
251
|
-
|
252
|
-
async function getTotalTxCostForBuy(tx: PreparedTransaction, from?: string) {
|
253
|
-
try {
|
254
|
-
const gasCost = await estimateGasCost({
|
255
|
-
transaction: tx,
|
256
|
-
from,
|
257
|
-
});
|
258
|
-
|
259
|
-
const bufferCost = gasCost.wei / 10n;
|
260
|
-
|
261
|
-
// Note: get tx.value AFTER estimateGasCost
|
262
|
-
const txValue = await resolvePromisedValue(tx.value);
|
263
|
-
|
264
|
-
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
|
265
|
-
return gasCost.wei + bufferCost + (txValue || 0n);
|
266
|
-
} catch {
|
267
|
-
if (from) {
|
268
|
-
// try again without passing from
|
269
|
-
return await getTotalTxCostForBuy(tx);
|
270
|
-
}
|
271
|
-
// fallback if both fail, use the tx value + 2M * gas price
|
272
|
-
const value = await resolvePromisedValue(tx.value);
|
273
|
-
|
274
|
-
const gasPrice = await getGasPrice({
|
275
|
-
client: tx.client,
|
276
|
-
chain: tx.chain,
|
277
|
-
});
|
278
|
-
|
279
|
-
const buffer = 2_000_000n * gasPrice;
|
280
|
-
|
281
|
-
if (!value) {
|
282
|
-
return 0n + buffer;
|
283
|
-
}
|
284
|
-
return value + buffer;
|
285
|
-
}
|
286
|
-
}
|
@@ -4,10 +4,9 @@ import { getChainMetadata } from "../../../../../../../chains/utils.js";
|
|
4
4
|
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
|
5
5
|
import { getContract } from "../../../../../../../contract/contract.js";
|
6
6
|
import { getCurrencyMetadata } from "../../../../../../../extensions/erc20/read/getCurrencyMetadata.js";
|
7
|
-
import { getGasPrice } from "../../../../../../../gas/get-gas-price.js";
|
8
7
|
import { encode } from "../../../../../../../transaction/actions/encode.js";
|
9
|
-
import { estimateGasCost } from "../../../../../../../transaction/actions/estimate-gas-cost.js";
|
10
8
|
import type { PreparedTransaction } from "../../../../../../../transaction/prepare-transaction.js";
|
9
|
+
import { getTransactionGasCost } from "../../../../../../../transaction/utils.js";
|
11
10
|
import type { Hex } from "../../../../../../../utils/encoding/hex.js";
|
12
11
|
import { resolvePromisedValue } from "../../../../../../../utils/promise/resolve-promised-value.js";
|
13
12
|
import type { Account } from "../../../../../../../wallets/interfaces/wallet.js";
|
@@ -138,30 +137,3 @@ export function useTransactionCostAndData(args: {
|
|
138
137
|
},
|
139
138
|
});
|
140
139
|
}
|
141
|
-
|
142
|
-
async function getTransactionGasCost(tx: PreparedTransaction, from?: string) {
|
143
|
-
try {
|
144
|
-
const gasCost = await estimateGasCost({
|
145
|
-
transaction: tx,
|
146
|
-
from,
|
147
|
-
});
|
148
|
-
|
149
|
-
const bufferCost = gasCost.wei / 10n;
|
150
|
-
|
151
|
-
// Note: get tx.value AFTER estimateGasCost
|
152
|
-
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
|
153
|
-
return gasCost.wei + bufferCost;
|
154
|
-
} catch {
|
155
|
-
if (from) {
|
156
|
-
// try again without passing from
|
157
|
-
return await getTransactionGasCost(tx);
|
158
|
-
}
|
159
|
-
// fallback if both fail, use the tx value + 2M * gas price
|
160
|
-
const gasPrice = await getGasPrice({
|
161
|
-
client: tx.client,
|
162
|
-
chain: tx.chain,
|
163
|
-
});
|
164
|
-
|
165
|
-
return 2_000_000n * gasPrice;
|
166
|
-
}
|
167
|
-
}
|
@@ -173,7 +173,11 @@ export async function getZkGasFees(args: {
|
|
173
173
|
resolvePromisedValue(transaction.eip712),
|
174
174
|
]);
|
175
175
|
let gasPerPubdata = eip712?.gasPerPubdata;
|
176
|
-
if (
|
176
|
+
if (
|
177
|
+
gas === undefined ||
|
178
|
+
maxFeePerGas === undefined ||
|
179
|
+
maxPriorityFeePerGas === undefined
|
180
|
+
) {
|
177
181
|
const rpc = getRpcClient(transaction);
|
178
182
|
const params = await formatTransaction({ transaction, from });
|
179
183
|
const result = (await rpc({
|
package/src/transaction/utils.ts
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
import type { AbiFunction } from "abitype";
|
2
|
+
import { getGasPrice } from "../gas/get-gas-price.js";
|
3
|
+
import { estimateGasCost } from "./actions/estimate-gas-cost.js";
|
4
|
+
import type { PreparedTransaction } from "./prepare-transaction.js";
|
2
5
|
|
3
6
|
/**
|
4
7
|
* @internal
|
@@ -11,3 +14,33 @@ export function isAbiFunction(item: unknown): item is AbiFunction {
|
|
11
14
|
item.type === "function"
|
12
15
|
);
|
13
16
|
}
|
17
|
+
|
18
|
+
export async function getTransactionGasCost(
|
19
|
+
tx: PreparedTransaction,
|
20
|
+
from?: string,
|
21
|
+
) {
|
22
|
+
try {
|
23
|
+
const gasCost = await estimateGasCost({
|
24
|
+
transaction: tx,
|
25
|
+
from,
|
26
|
+
});
|
27
|
+
|
28
|
+
const bufferCost = gasCost.wei / 10n;
|
29
|
+
|
30
|
+
// Note: get tx.value AFTER estimateGasCost
|
31
|
+
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
|
32
|
+
return gasCost.wei + bufferCost;
|
33
|
+
} catch {
|
34
|
+
if (from) {
|
35
|
+
// try again without passing from
|
36
|
+
return await getTransactionGasCost(tx);
|
37
|
+
}
|
38
|
+
// fallback if both fail, use the tx value + 1M * gas price
|
39
|
+
const gasPrice = await getGasPrice({
|
40
|
+
client: tx.client,
|
41
|
+
chain: tx.chain,
|
42
|
+
});
|
43
|
+
|
44
|
+
return 1_000_000n * gasPrice;
|
45
|
+
}
|
46
|
+
}
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.73.0-nightly-ea855c66cb940d1adafefaad6dd689227701d277-20241203000359";
|