Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a58d116314 | ||
|
|
ad24d83b51 | ||
|
|
9d142f53b4 | ||
|
|
74023c61c8 | ||
|
|
63b186cc94 | ||
|
|
9d410c6a54 | ||
|
|
02c03196ad | ||
|
|
a8667f8090 | ||
|
|
691672f864 | ||
|
|
cbdda89963 | ||
|
|
55081d8335 | ||
|
|
ef1b7cdb90 | ||
|
|
2a85f9c5ea | ||
|
|
83cdef01d1 | ||
|
|
d331921aaf | ||
|
|
579d5b5019 | ||
|
|
209825baca | ||
|
|
0aae34bdb8 |
@@ -8,8 +8,7 @@
|
||||
],
|
||||
"commit": false,
|
||||
"fixed": [
|
||||
["@thirdweb-dev/react-core", "@thirdweb-dev/react"],
|
||||
["@thirdweb-dev/react-native-compat", "@thirdweb-dev/react-native"]
|
||||
["@thirdweb-dev/react-core", "@thirdweb-dev/react"]
|
||||
],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
|
||||
Vendored
+6
-2
@@ -5,11 +5,15 @@
|
||||
"quickfix.biome": "explicit",
|
||||
"source.organizeImports.biome": "explicit"
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": "relative",
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"typescript.preferences.autoImportFileExcludePatterns": ["/exports"],
|
||||
"typescript.preferences.importModuleSpecifier": "relative"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 4.1.77
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/wallets@2.5.19
|
||||
|
||||
## 4.1.76
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.5.18
|
||||
|
||||
## 4.1.75
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "4.1.75",
|
||||
"version": "4.1.77",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.108
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.1.107
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2982](https://github.com/thirdweb-dev/js/pull/2982) [`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf) Thanks [@github-actions](https://github.com/apps/github-actions)! - Synced Chains Package
|
||||
|
||||
## 0.1.106
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Silicon",
|
||||
"chainId": 1414,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmTEnk2fosqbY6HQW5vySrLGbopJfeni9ThZ6R9sVefbnq",
|
||||
"width": 800,
|
||||
"height": 800,
|
||||
"format": "png"
|
||||
},
|
||||
"name": "Silicon zkEVM Sepolia Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Sepolia Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 1414,
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-11155111",
|
||||
"bridges": []
|
||||
},
|
||||
"rpc": [],
|
||||
"shortName": "silicon-sepolia-testnet",
|
||||
"slug": "silicon-zkevm-sepolia-testnet",
|
||||
"status": "incubating",
|
||||
"testnet": true,
|
||||
"title": "Silicon zkEVM Sepolia Testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -12,6 +12,11 @@ export default {
|
||||
"name": "Omni EVM Explorer on Blockscout",
|
||||
"url": "https://omni-testnet.blockscout.com",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Omni EVM Explorer on Routescan",
|
||||
"url": "https://testnet.omniscan.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
@@ -21,17 +26,20 @@ export default {
|
||||
}
|
||||
],
|
||||
"infoURL": "https://docs.omni.network",
|
||||
"name": "Omni Testnet (incubating)",
|
||||
"name": "Omni Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Omni",
|
||||
"symbol": "OMNI",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 164,
|
||||
"rpc": [],
|
||||
"shortName": "omni_testnet_164",
|
||||
"rpc": [
|
||||
"https://164.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.omni.network"
|
||||
],
|
||||
"shortName": "omni_testnet",
|
||||
"slip44": 1,
|
||||
"slug": "omni-testnet-incubating",
|
||||
"status": "incubating",
|
||||
"slug": "omni-testnet",
|
||||
"status": "active",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -2,13 +2,7 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Omni",
|
||||
"chainId": 165,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Omni Explorer",
|
||||
"url": "https://testnet.explorer.omni.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"features": [
|
||||
{
|
||||
@@ -16,19 +10,17 @@ export default {
|
||||
}
|
||||
],
|
||||
"infoURL": "https://docs.omni.network/",
|
||||
"name": "Omni Testnet",
|
||||
"name": "Omni Testnet (Deprecated)",
|
||||
"nativeCurrency": {
|
||||
"name": "Omni",
|
||||
"symbol": "OMNI",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 165,
|
||||
"rpc": [
|
||||
"https://165.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.omni.network"
|
||||
],
|
||||
"shortName": "omni_testnet",
|
||||
"rpc": [],
|
||||
"shortName": "omni_testnet_deprecated",
|
||||
"slip44": 1,
|
||||
"slug": "omni-testnet",
|
||||
"slug": "omni-testnet-deprecated",
|
||||
"status": "deprecated",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Silicon",
|
||||
"chainId": 2355,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://QmTEnk2fosqbY6HQW5vySrLGbopJfeni9ThZ6R9sVefbnq",
|
||||
"width": 800,
|
||||
"height": 800,
|
||||
"format": "png"
|
||||
},
|
||||
"name": "Silicon zkEVM",
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 2355,
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-1",
|
||||
"bridges": []
|
||||
},
|
||||
"rpc": [],
|
||||
"shortName": "silicon-zk",
|
||||
"slug": "silicon-zkevm",
|
||||
"status": "incubating",
|
||||
"testnet": false,
|
||||
"title": "Silicon zkEVM Mainnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Avalanche",
|
||||
"chainId": 3070,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"features": [],
|
||||
"icon": {
|
||||
"url": "https://images.ctfassets.net/9bazykntljf6/62CceHSYsRS4D9fgDSkLRB/877cb8f26954e1743ff535fd7fdaf78f/avacloud-placeholder.svg",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "svg"
|
||||
},
|
||||
"infoURL": "https://avacloud.io",
|
||||
"name": "QaUser9054",
|
||||
"nativeCurrency": {
|
||||
"name": "QaUser9054 Token",
|
||||
"symbol": "QFE",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 3070,
|
||||
"redFlags": [],
|
||||
"rpc": [
|
||||
"https://3070.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc"
|
||||
],
|
||||
"shortName": "QaUser9054",
|
||||
"slug": "qauser9054",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Avalanche",
|
||||
"chainId": 59940,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"features": [],
|
||||
"icon": {
|
||||
"url": "https://images.ctfassets.net/9bazykntljf6/62CceHSYsRS4D9fgDSkLRB/877cb8f26954e1743ff535fd7fdaf78f/avacloud-placeholder.svg",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "svg"
|
||||
},
|
||||
"infoURL": "https://avacloud.io",
|
||||
"name": "QR0510s1",
|
||||
"nativeCurrency": {
|
||||
"name": "QR0510s1 Token",
|
||||
"symbol": "RTQ",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 59940,
|
||||
"redFlags": [],
|
||||
"rpc": [
|
||||
"https://59940.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/qr0510s1/testnet/rpc"
|
||||
],
|
||||
"shortName": "QR0510s1",
|
||||
"slug": "qr0510s1",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"chain": "Avalanche",
|
||||
"chainId": 767368,
|
||||
"explorers": [],
|
||||
"faucets": [],
|
||||
"features": [],
|
||||
"icon": {
|
||||
"url": "https://images.ctfassets.net/9bazykntljf6/62CceHSYsRS4D9fgDSkLRB/877cb8f26954e1743ff535fd7fdaf78f/avacloud-placeholder.svg",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "svg"
|
||||
},
|
||||
"infoURL": "https://avacloud.io",
|
||||
"name": "Lamina1 Identity Testnet",
|
||||
"nativeCurrency": {
|
||||
"name": "Lamina1 Identity Testnet Token",
|
||||
"symbol": "L1IDT",
|
||||
"decimals": 18
|
||||
},
|
||||
"networkId": 767368,
|
||||
"redFlags": [],
|
||||
"rpc": [
|
||||
"https://767368.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/lamina1id/testnet/rpc"
|
||||
],
|
||||
"shortName": "Lamina1 Identity Testnet",
|
||||
"slug": "lamina1-identity-testnet",
|
||||
"testnet": true
|
||||
} as const satisfies Chain;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.106",
|
||||
"version": "0.1.108",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"exports": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,28 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.13.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/auth@4.1.77
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/sdk@4.0.79
|
||||
- @thirdweb-dev/storage@2.0.15
|
||||
- @thirdweb-dev/wallets@2.5.19
|
||||
|
||||
## 0.13.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
- @thirdweb-dev/sdk@4.0.78
|
||||
- @thirdweb-dev/wallets@2.5.18
|
||||
- @thirdweb-dev/auth@4.1.76
|
||||
|
||||
## 0.13.83
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/cli",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.13.83",
|
||||
"version": "0.13.85",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.3.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 1.3.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.3.22",
|
||||
"version": "1.3.23",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/crypto
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/crypto",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6",
|
||||
"main": "dist/thirdweb-dev-crypto.cjs.js",
|
||||
"module": "dist/thirdweb-dev-crypto.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/generated-abis
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/generated-abis",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"main": "dist/thirdweb-dev-generated-abis.cjs.js",
|
||||
"module": "dist/thirdweb-dev-generated-abis.esm.js",
|
||||
"browser": {
|
||||
@@ -23,7 +23,9 @@
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"sideEffects": false,
|
||||
"files": ["dist/"],
|
||||
"files": [
|
||||
"dist/"
|
||||
],
|
||||
"scripts": {
|
||||
"push": "yalc push"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/merkletree
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/merkletree",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6",
|
||||
"main": "dist/thirdweb-dev-merkletree.cjs.js",
|
||||
"module": "dist/thirdweb-dev-merkletree.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/pay
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/pay",
|
||||
"version": "0.1.7",
|
||||
"version": "0.1.8",
|
||||
"main": "dist/thirdweb-dev-pay.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/payments
|
||||
|
||||
## 1.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/payments",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"main": "dist/thirdweb-dev-payments.cjs.js",
|
||||
"module": "dist/thirdweb-dev-payments.esm.js",
|
||||
"types": "dist/thirdweb-dev-payments.cjs.d.ts",
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 4.6.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/auth@4.1.77
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/generated-abis@0.0.2
|
||||
- @thirdweb-dev/sdk@4.0.79
|
||||
- @thirdweb-dev/storage@2.0.15
|
||||
- @thirdweb-dev/wallets@2.5.19
|
||||
|
||||
## 4.6.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
- @thirdweb-dev/sdk@4.0.78
|
||||
- @thirdweb-dev/wallets@2.5.18
|
||||
- @thirdweb-dev/auth@4.1.76
|
||||
|
||||
## 4.6.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "4.6.16",
|
||||
"version": "4.6.18",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
Binary file not shown.
@@ -50,11 +50,11 @@
|
||||
"devDependencies": {
|
||||
"@react-native-async-storage/async-storage": "^1.23.1",
|
||||
"@react-native-community/eslint-config": "^3.2.0",
|
||||
"@thirdweb-dev/tsconfig": "^0.1.7",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/react": "18.2.17",
|
||||
"@types/react-native": "^0.71.13",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-thirdweb": "^0.1.9",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-i18next": "^6.0.3",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-inclusive-language": "^2.2.1",
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 4.6.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/payments@1.0.5
|
||||
- @thirdweb-dev/react-core@4.6.18
|
||||
- @thirdweb-dev/sdk@4.0.79
|
||||
- @thirdweb-dev/wallets@2.5.19
|
||||
|
||||
## 4.6.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2985](https://github.com/thirdweb-dev/js/pull/2985) [`55081d8`](https://github.com/thirdweb-dev/js/commit/55081d833585b8c7c24690abd87cabeee95cde33) Thanks [@jnsdls](https://github.com/jnsdls)! - thirdweb Pay UI minor improvements
|
||||
|
||||
- Updated dependencies [[`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
- @thirdweb-dev/sdk@4.0.78
|
||||
- @thirdweb-dev/react-core@4.6.17
|
||||
- @thirdweb-dev/wallets@2.5.18
|
||||
|
||||
## 4.6.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "4.6.16",
|
||||
"version": "4.6.18",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { getBuyWithCryptoStatus } from "@thirdweb-dev/sdk";
|
||||
import type { BuyWithCryptoStatus } from "@thirdweb-dev/sdk";
|
||||
import { getBuyWithCryptoStatus, type BuyWithCryptoStatus } from "@thirdweb-dev/sdk";
|
||||
import { wait } from "../../../../../utils/wait";
|
||||
|
||||
type ValidBuyWithCryptoStatus = Exclude<BuyWithCryptoStatus, { status: 'NOT_FOUND'}>
|
||||
|
||||
type SwapTxInfo = {
|
||||
transactionHash: string;
|
||||
status: BuyWithCryptoStatus["status"];
|
||||
subStatus?: BuyWithCryptoStatus["subStatus"];
|
||||
status: ValidBuyWithCryptoStatus["status"];
|
||||
subStatus?: ValidBuyWithCryptoStatus["subStatus"];
|
||||
source: {
|
||||
symbol: string;
|
||||
value: string;
|
||||
|
||||
@@ -24,13 +24,16 @@ import { BuyIcon } from "../icons/BuyIcon";
|
||||
import { Text } from "../../../components/text";
|
||||
import { CryptoIcon } from "../icons/CryptoIcon";
|
||||
|
||||
type ValidBuyWithCryptoStatus = Exclude<BuyWithCryptoStatus, { status: 'NOT_FOUND'}>
|
||||
|
||||
|
||||
type TxStatusInfo = {
|
||||
boughChainId: number;
|
||||
transactionHash: string;
|
||||
boughtTokenAmount: string;
|
||||
boughtTokenSymbol: string;
|
||||
status: BuyWithCryptoStatus["status"];
|
||||
subStatus?: BuyWithCryptoStatus["subStatus"];
|
||||
status: ValidBuyWithCryptoStatus["status"];
|
||||
subStatus?: ValidBuyWithCryptoStatus["subStatus"];
|
||||
};
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
@@ -51,7 +54,11 @@ export function SwapTransactionsScreen(props: { onBack: () => void }) {
|
||||
|
||||
const txHashSet = new Set<string>();
|
||||
_historyQuery.data?.page.forEach((tx) => {
|
||||
txHashSet.add(tx.source.transactionHash);
|
||||
if (tx.status !== "NOT_FOUND" && tx.status !== 'NONE') {
|
||||
if (tx.source?.transactionHash) {
|
||||
txHashSet.add(tx.source?.transactionHash);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add in-memory pending transactions
|
||||
@@ -76,15 +83,20 @@ export function SwapTransactionsScreen(props: { onBack: () => void }) {
|
||||
|
||||
// Add data from endpoint
|
||||
_historyQuery.data?.page.forEach((tx) => {
|
||||
txInfosToShow.push({
|
||||
boughChainId: tx.destination?.token.chainId || tx.quote.toToken.chainId,
|
||||
transactionHash: tx.source.transactionHash,
|
||||
boughtTokenAmount: tx.destination?.amount || tx.quote.toAmount,
|
||||
boughtTokenSymbol:
|
||||
tx.destination?.token.symbol || tx.quote.toToken.symbol || "",
|
||||
status: tx.status,
|
||||
subStatus: tx.subStatus,
|
||||
});
|
||||
if (tx.status !== "NOT_FOUND" && tx.status !== 'NONE') {
|
||||
if (tx.source?.transactionHash) {
|
||||
txInfosToShow.push({
|
||||
boughChainId:
|
||||
tx.destination?.token.chainId || tx.quote.toToken.chainId,
|
||||
transactionHash: tx.source?.transactionHash,
|
||||
boughtTokenAmount: tx.destination?.amount || tx.quote.toAmount,
|
||||
boughtTokenSymbol:
|
||||
tx.destination?.token.symbol || tx.quote.toToken.symbol || "",
|
||||
status: tx.status,
|
||||
subStatus: tx.subStatus,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const activeChainId = useChainId();
|
||||
@@ -367,8 +379,8 @@ const TxHashLink = /* @__PURE__ */ StyledAnchor(() => {
|
||||
});
|
||||
|
||||
function getStatusMeta(
|
||||
status: BuyWithCryptoStatus["status"],
|
||||
subStatus?: BuyWithCryptoStatus["subStatus"],
|
||||
status: ValidBuyWithCryptoStatus["status"],
|
||||
subStatus?: ValidBuyWithCryptoStatus["subStatus"],
|
||||
) {
|
||||
if (subStatus === "WAITING_BRIDGE") {
|
||||
return {
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,28 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 4.0.79
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/contracts-js@1.3.23
|
||||
- @thirdweb-dev/crypto@0.2.6
|
||||
- @thirdweb-dev/generated-abis@0.0.2
|
||||
- @thirdweb-dev/merkletree@0.2.6
|
||||
- @thirdweb-dev/storage@2.0.15
|
||||
- thirdweb@5.18.1
|
||||
|
||||
## 4.0.78
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`55081d8`](https://github.com/thirdweb-dev/js/commit/55081d833585b8c7c24690abd87cabeee95cde33), [`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- thirdweb@5.18.0
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
|
||||
## 4.0.77
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "4.0.77",
|
||||
"version": "4.0.79",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,14 @@
|
||||
# @thirdweb-dev/storage
|
||||
|
||||
## 2.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/crypto@0.2.6
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/storage",
|
||||
"version": "2.0.14",
|
||||
"version": "2.0.15",
|
||||
"main": "dist/thirdweb-dev-storage.cjs.js",
|
||||
"module": "dist/thirdweb-dev-storage.esm.js",
|
||||
"exports": {
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,29 @@
|
||||
# @thirdweb-dev/unity-js-bridge
|
||||
|
||||
## 0.6.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/auth@4.1.77
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/pay@0.1.8
|
||||
- @thirdweb-dev/sdk@4.0.79
|
||||
- @thirdweb-dev/storage@2.0.15
|
||||
- @thirdweb-dev/wallets@2.5.19
|
||||
|
||||
## 0.6.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
- @thirdweb-dev/sdk@4.0.78
|
||||
- @thirdweb-dev/wallets@2.5.18
|
||||
- @thirdweb-dev/auth@4.1.76
|
||||
|
||||
## 0.6.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/unity-js-bridge",
|
||||
"version": "0.6.26",
|
||||
"version": "0.6.28",
|
||||
"main": "dist/thirdweb-unity-bridge.js",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @thirdweb-dev/wallets
|
||||
|
||||
## 2.5.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
- Updated dependencies [[`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60)]:
|
||||
- @thirdweb-dev/chains@0.1.108
|
||||
- @thirdweb-dev/contracts-js@1.3.23
|
||||
- @thirdweb-dev/crypto@0.2.6
|
||||
- @thirdweb-dev/sdk@4.0.79
|
||||
|
||||
## 2.5.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef1b7cd`](https://github.com/thirdweb-dev/js/commit/ef1b7cdb90aaa4c33cf0c7f619cab0d4d4acfccf)]:
|
||||
- @thirdweb-dev/chains@0.1.107
|
||||
- @thirdweb-dev/sdk@4.0.78
|
||||
|
||||
## 2.5.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/wallets",
|
||||
"version": "2.5.17",
|
||||
"version": "2.5.19",
|
||||
"main": "dist/thirdweb-dev-wallets.cjs.js",
|
||||
"module": "dist/thirdweb-dev-wallets.esm.js",
|
||||
"browser": {
|
||||
|
||||
Binary file not shown.
@@ -50,6 +50,11 @@
|
||||
},
|
||||
"_______ALL_PACKAGE_DEV_DEPENDENCIES_GO_IN_HERE_SO_CONSUMERS_DONT_END_UP_INSTALLING_THEM______": "_______ALL_PACKAGE_DEV_DEPENDENCIES_GO_IN_HERE_SO_CONSUMERS_DONT_END_UP_INSTALLING_THEM______",
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-transform-flow-strip-types": "^7.24.1",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.1",
|
||||
"@babel/preset-env": "^7.24.5",
|
||||
"@babel/preset-typescript": "^7.24.1",
|
||||
"@biomejs/biome": "1.7.1",
|
||||
"@codspeed/vitest-plugin": "3.1.0",
|
||||
"@size-limit/preset-big-lib": "11.1.2",
|
||||
@@ -60,6 +65,11 @@
|
||||
"dotenv-mono": "1.3.14",
|
||||
"ethers5": "npm:[email protected]",
|
||||
"ethers6": "npm:[email protected]",
|
||||
"eslint-plugin-i18next": "^6.0.3",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-inclusive-language": "^2.2.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-tsdoc": "^0.2.17",
|
||||
"knip": "5.9.4",
|
||||
"mitata": "0.1.11",
|
||||
"react": "18.2.0",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/service-utils
|
||||
|
||||
## 0.4.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 0.4.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/service-utils",
|
||||
"version": "0.4.28",
|
||||
"version": "0.4.29",
|
||||
"main": "dist/thirdweb-dev-service-utils.cjs.js",
|
||||
"module": "dist/thirdweb-dev-service-utils.esm.js",
|
||||
"exports": {
|
||||
|
||||
@@ -1,5 +1,62 @@
|
||||
# thirdweb
|
||||
|
||||
## 5.18.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2988](https://github.com/thirdweb-dev/js/pull/2988) [`02c0319`](https://github.com/thirdweb-dev/js/commit/02c03196ad38de888ff86311c68fa010018bda60) Thanks [@jnsdls](https://github.com/jnsdls)! - bump all to fix release
|
||||
|
||||
## 5.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#2985](https://github.com/thirdweb-dev/js/pull/2985) [`55081d8`](https://github.com/thirdweb-dev/js/commit/55081d833585b8c7c24690abd87cabeee95cde33) Thanks [@jnsdls](https://github.com/jnsdls)! - ### "Credit Card" payment method added in thirdweb Pay for Fiat on-ramp
|
||||
|
||||
### `PayEmbed` component added to embed thirdweb Pay UI
|
||||
|
||||
```tsx
|
||||
<PayEmbed
|
||||
client={client}
|
||||
style={{
|
||||
width: "360px",
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### thirdweb Pay UI customization available in `PayEmbed` and `ConnectButton`
|
||||
|
||||
`payOptions` prop in `PayEmbed` and `ConnectButton > detailsModal` allows you custimize :
|
||||
|
||||
- Enable/Disable payment methods
|
||||
- Set default amount for Buy token
|
||||
- Set Buy token/chain to be selected by default
|
||||
- Set Source token/chain to be selected by default for Crypto payment method
|
||||
- Disable editing for Buy token/chain/amount and Source token/chain
|
||||
|
||||
```tsx
|
||||
<ConnectButton
|
||||
client={client}
|
||||
detailsModal={{
|
||||
payOptions: yourOptions,
|
||||
}}
|
||||
/>
|
||||
|
||||
<PayEmbed
|
||||
client={client}
|
||||
detailsModal={{
|
||||
payOptions: yourOptions,
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Fiat on-ramp functions and hooks added
|
||||
|
||||
- `getBuyWithFiatQuote`, `useBuyWithFiatQuote` to get a quote for buying crypto with fiat currency
|
||||
- `getBuyWithFiatStatus`, `useBuyWithFiatStatus` to get status of "Buy with fiat" transaction
|
||||
- `getBuyWithFiatHistory`, `useBuyWithFiatHistory` to get "Buy with fiat" transaction history
|
||||
- `getPostOnRampQuote`, `usePostOnRampQuote` to get quote for swapping on-ramp token to destination token after doing on-ramp
|
||||
- Add `getBuyHistory` and `useBuyHistory` to get both "Buy with Fiat" and "Buy with Crypto" transaction history in a single list
|
||||
|
||||
## 5.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"version": "5.17.0",
|
||||
"version": "5.18.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/thirdweb-dev/js.git#main"
|
||||
@@ -241,6 +241,7 @@
|
||||
"@testing-library/jest-dom": "^6.4.5",
|
||||
"@testing-library/react": "^15.0.6",
|
||||
"@types/cross-spawn": "^6.0.6",
|
||||
"@types/react": "18.2.17",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@vitest/ui": "1.5.0",
|
||||
"cross-spawn": "7.0.3",
|
||||
|
||||
@@ -4,17 +4,56 @@ export {
|
||||
type QuoteApprovalParams,
|
||||
type QuoteTokenInfo,
|
||||
type GetBuyWithCryptoQuoteParams,
|
||||
} from "../pay/buyWithCrypto/actions/getQuote.js";
|
||||
} from "../pay/buyWithCrypto/getQuote.js";
|
||||
|
||||
export {
|
||||
getBuyWithCryptoStatus,
|
||||
type BuyWithCryptoStatus,
|
||||
type BuyWithCryptoTransaction,
|
||||
type BuyWithCryptoTransactionDetails,
|
||||
} from "../pay/buyWithCrypto/actions/getStatus.js";
|
||||
} from "../pay/buyWithCrypto/getStatus.js";
|
||||
|
||||
export {
|
||||
getBuyWithCryptoHistory,
|
||||
type BuyWithCryptoHistoryData,
|
||||
type BuyWithCryptoHistoryParams,
|
||||
} from "../pay/buyWithCrypto/actions/getHistory.js";
|
||||
} from "../pay/buyWithCrypto/getHistory.js";
|
||||
|
||||
// fiat ------------------------------------------------
|
||||
|
||||
export {
|
||||
getBuyWithFiatQuote,
|
||||
type BuyWithFiatQuote,
|
||||
type GetBuyWithFiatQuoteParams,
|
||||
} from "../pay/buyWithFiat/getQuote.js";
|
||||
|
||||
export {
|
||||
getBuyWithFiatStatus,
|
||||
type BuyWithFiatStatus,
|
||||
type GetBuyWithFiatStatusParams,
|
||||
} from "../pay/buyWithFiat/getStatus.js";
|
||||
|
||||
export {
|
||||
getBuyWithFiatHistory,
|
||||
type BuyWithFiatHistoryData,
|
||||
type BuyWithFiatHistoryParams,
|
||||
} from "../pay/buyWithFiat/getHistory.js";
|
||||
|
||||
export {
|
||||
getPostOnRampQuote,
|
||||
type GetPostOnRampQuoteParams,
|
||||
} from "../pay/buyWithFiat/getPostOnRampQuote.js";
|
||||
|
||||
export {
|
||||
getBuyHistory,
|
||||
type BuyHistoryData,
|
||||
type BuyHistoryParams,
|
||||
} from "../pay/getBuyHistory.js";
|
||||
|
||||
export { isSwapRequiredPostOnramp } from "../pay/buyWithFiat/isSwapRequiredPostOnramp.js";
|
||||
|
||||
// types ------------------------------------------------
|
||||
|
||||
export type {
|
||||
PayTokenInfo,
|
||||
PayOnChainTransactionDetails,
|
||||
} from "../pay/utils/commonTypes.js";
|
||||
|
||||
@@ -32,19 +32,33 @@ export {
|
||||
export { createContractQuery } from "../react/core/utils/createQuery.js";
|
||||
export { useInvalidateContractQuery } from "../react/core/hooks/others/useInvalidateQueries.js";
|
||||
|
||||
// Buy with crypto
|
||||
// pay
|
||||
export {
|
||||
useBuyWithCryptoQuote,
|
||||
type BuyWithCryptoQuoteQueryParams,
|
||||
type BuyWithCryptoQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoQuote.js";
|
||||
export {
|
||||
useBuyWithCryptoStatus,
|
||||
type BuyWithCryptoStatusQueryParams,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
|
||||
export { useBuyWithCryptoStatus } from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
|
||||
export {
|
||||
useBuyWithCryptoHistory,
|
||||
type BuyWithCryptoHistoryQueryParams,
|
||||
type BuyWithCryptoHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoHistory.js";
|
||||
export {
|
||||
useBuyWithFiatQuote,
|
||||
type BuyWithFiatQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithFiatQuote.js";
|
||||
export { useBuyWithFiatStatus } from "../react/core/hooks/pay/useBuyWithFiatStatus.js";
|
||||
export {
|
||||
useBuyWithFiatHistory,
|
||||
type BuyWithFiatHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithFiatHistory.js";
|
||||
export {
|
||||
useBuyHistory,
|
||||
type BuyHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyHistory.js";
|
||||
export {
|
||||
usePostOnRampQuote,
|
||||
type PostOnRampQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/usePostOnrampQuote.js";
|
||||
|
||||
import { useSendTransactionCore } from "../react/core/hooks/contract/useSendTransaction.js";
|
||||
|
||||
|
||||
@@ -80,20 +80,33 @@ export {
|
||||
export { createContractQuery } from "../react/core/utils/createQuery.js";
|
||||
export { useInvalidateContractQuery } from "../react/core/hooks/others/useInvalidateQueries.js";
|
||||
|
||||
// Buy with crypto
|
||||
// pay
|
||||
export {
|
||||
useBuyWithCryptoQuote,
|
||||
type BuyWithCryptoQuoteQueryParams,
|
||||
type BuyWithCryptoQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoQuote.js";
|
||||
|
||||
export {
|
||||
useBuyWithCryptoStatus,
|
||||
type BuyWithCryptoStatusQueryParams,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
|
||||
export { useBuyWithCryptoStatus } from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
|
||||
export {
|
||||
useBuyWithCryptoHistory,
|
||||
type BuyWithCryptoHistoryQueryParams,
|
||||
type BuyWithCryptoHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithCryptoHistory.js";
|
||||
export {
|
||||
useBuyWithFiatQuote,
|
||||
type BuyWithFiatQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithFiatQuote.js";
|
||||
export { useBuyWithFiatStatus } from "../react/core/hooks/pay/useBuyWithFiatStatus.js";
|
||||
export {
|
||||
useBuyWithFiatHistory,
|
||||
type BuyWithFiatHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyWithFiatHistory.js";
|
||||
export {
|
||||
useBuyHistory,
|
||||
type BuyHistoryQueryOptions,
|
||||
} from "../react/core/hooks/pay/useBuyHistory.js";
|
||||
export {
|
||||
usePostOnRampQuote,
|
||||
type PostOnRampQuoteQueryOptions,
|
||||
} from "../react/core/hooks/pay/usePostOnrampQuote.js";
|
||||
|
||||
export {
|
||||
AutoConnect,
|
||||
@@ -102,3 +115,10 @@ export {
|
||||
|
||||
// auth
|
||||
export { type SiweAuthOptions } from "../react/core/hooks/auth/useSiweAuth.js";
|
||||
|
||||
export {
|
||||
PayEmbed,
|
||||
type PayEmbedProps,
|
||||
type PayEmbedConnectOptions,
|
||||
} from "../react/web/ui/PayEmbed.js";
|
||||
export type { PayUIOptions } from "../react/web/ui/ConnectWallet/ConnectButtonProps.js";
|
||||
|
||||
@@ -156,20 +156,24 @@ export {
|
||||
type QuoteApprovalParams,
|
||||
type QuoteTokenInfo,
|
||||
type GetBuyWithCryptoQuoteParams,
|
||||
} from "../pay/buyWithCrypto/actions/getQuote.js";
|
||||
} from "../pay/buyWithCrypto/getQuote.js";
|
||||
|
||||
export {
|
||||
getBuyWithCryptoStatus,
|
||||
type BuyWithCryptoStatus,
|
||||
type BuyWithCryptoTransaction,
|
||||
type BuyWithCryptoTransactionDetails,
|
||||
} from "../pay/buyWithCrypto/actions/getStatus.js";
|
||||
} from "../pay/buyWithCrypto/getStatus.js";
|
||||
|
||||
export {
|
||||
getBuyWithCryptoHistory,
|
||||
type BuyWithCryptoHistoryData,
|
||||
type BuyWithCryptoHistoryParams,
|
||||
} from "../pay/buyWithCrypto/actions/getHistory.js";
|
||||
} from "../pay/buyWithCrypto/getHistory.js";
|
||||
|
||||
export type {
|
||||
PayOnChainTransactionDetails,
|
||||
PayTokenInfo,
|
||||
} from "../pay/utils/commonTypes.js";
|
||||
|
||||
// ------------------------------------------------
|
||||
// encoding
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import type { ThirdwebClient } from "../../../client/client.js";
|
||||
import { getClientFetch } from "../../../utils/fetch.js";
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import { getPayBuyWithCryptoHistoryEndpoint } from "../utils/definitions.js";
|
||||
import type { BuyWithCryptoStatus } from "./getStatus.js";
|
||||
|
||||
+20
-7
@@ -1,14 +1,14 @@
|
||||
import type { Hash } from "viem";
|
||||
import { defineChain } from "../../../chains/utils.js";
|
||||
import type { ThirdwebClient } from "../../../client/client.js";
|
||||
import { getContract } from "../../../contract/contract.js";
|
||||
import { defineChain } from "../../chains/utils.js";
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getContract } from "../../contract/contract.js";
|
||||
import {
|
||||
type ApproveParams,
|
||||
approve,
|
||||
} from "../../../extensions/erc20/write/approve.js";
|
||||
import type { PrepareTransactionOptions } from "../../../transaction/prepare-transaction.js";
|
||||
import type { BaseTransactionOptions } from "../../../transaction/types.js";
|
||||
import { getClientFetch } from "../../../utils/fetch.js";
|
||||
} from "../../extensions/erc20/write/approve.js";
|
||||
import type { PrepareTransactionOptions } from "../../transaction/prepare-transaction.js";
|
||||
import type { BaseTransactionOptions } from "../../transaction/types.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import { getPayBuyWithCryptoQuoteEndpoint } from "../utils/definitions.js";
|
||||
|
||||
// TODO: add JSDoc description for all properties
|
||||
@@ -27,6 +27,15 @@ export type GetBuyWithCryptoQuoteParams = {
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
|
||||
/**
|
||||
* This is only relevant if the buy-with-crypto transaction is part of buy-with-fiat flow.
|
||||
*
|
||||
* When a swap is required after an onramp transaction, the intentId is used to link the buy-with-crypto transaction to the onramp transaction.
|
||||
* Refer to [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) for more information.`
|
||||
*
|
||||
*/
|
||||
intentId?: string;
|
||||
|
||||
/**
|
||||
* The address of the wallet from which the tokens will be sent.
|
||||
*/
|
||||
@@ -240,6 +249,10 @@ export async function getBuyWithCryptoQuote(
|
||||
queryParams.append("maxSlippageBPS", params.maxSlippageBPS.toString());
|
||||
}
|
||||
|
||||
if (params.intentId) {
|
||||
queryParams.append("intentId", params.intentId);
|
||||
}
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const url = `${getPayBuyWithCryptoQuoteEndpoint()}?${queryString}`;
|
||||
|
||||
+44
-44
@@ -1,23 +1,16 @@
|
||||
import type { ThirdwebClient } from "../../../client/client.js";
|
||||
import { getClientFetch } from "../../../utils/fetch.js";
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import type {
|
||||
PayOnChainTransactionDetails,
|
||||
PayTokenInfo,
|
||||
} from "../utils/commonTypes.js";
|
||||
import { getPayBuyWithCryptoStatusUrl } from "../utils/definitions.js";
|
||||
import type { QuoteTokenInfo } from "./getQuote.js";
|
||||
|
||||
// TODO: add JSDoc description for all properties
|
||||
|
||||
export type BuyWithCryptoTransactionDetails = {
|
||||
transactionHash: string;
|
||||
token: QuoteTokenInfo;
|
||||
amountWei: string;
|
||||
amount: string;
|
||||
amountUSDCents: number;
|
||||
completedAt?: string; // ISO DATE
|
||||
explorerLink?: string;
|
||||
};
|
||||
|
||||
export type BuyWithCryptoQuoteSummary = {
|
||||
fromToken: QuoteTokenInfo;
|
||||
toToken: QuoteTokenInfo;
|
||||
fromToken: PayTokenInfo;
|
||||
toToken: PayTokenInfo;
|
||||
|
||||
fromAmountWei: string;
|
||||
fromAmount: string;
|
||||
@@ -46,12 +39,7 @@ export type BuyWithCryptoTransaction = {
|
||||
transactionHash: string;
|
||||
};
|
||||
|
||||
export type BuyWithCryptoStatuses =
|
||||
| "NOT_FOUND"
|
||||
| "NONE"
|
||||
| "PENDING"
|
||||
| "FAILED"
|
||||
| "COMPLETED";
|
||||
export type BuyWithCryptoStatuses = "NONE" | "PENDING" | "FAILED" | "COMPLETED";
|
||||
|
||||
export type BuyWithCryptoSubStatuses =
|
||||
| "NONE"
|
||||
@@ -67,18 +55,27 @@ export type SwapType = "SAME_CHAIN" | "CROSS_CHAIN";
|
||||
* The object returned by the [`getBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoStatus) function to represent the status of a quoted transaction
|
||||
* @buyCrypto
|
||||
*/
|
||||
export type BuyWithCryptoStatus = {
|
||||
quote: BuyWithCryptoQuoteSummary;
|
||||
swapType: SwapType;
|
||||
source: BuyWithCryptoTransactionDetails;
|
||||
destination?: BuyWithCryptoTransactionDetails;
|
||||
status: BuyWithCryptoStatuses;
|
||||
subStatus: BuyWithCryptoSubStatuses;
|
||||
fromAddress: string;
|
||||
toAddress: string;
|
||||
failureMessage?: string;
|
||||
bridge?: string;
|
||||
};
|
||||
export type BuyWithCryptoStatus =
|
||||
| {
|
||||
status: "NOT_FOUND";
|
||||
}
|
||||
| {
|
||||
quote: BuyWithCryptoQuoteSummary;
|
||||
swapType: SwapType;
|
||||
source?: PayOnChainTransactionDetails;
|
||||
destination?: PayOnChainTransactionDetails;
|
||||
status: BuyWithCryptoStatuses;
|
||||
subStatus: BuyWithCryptoSubStatuses;
|
||||
fromAddress: string;
|
||||
toAddress: string;
|
||||
failureMessage?: string;
|
||||
bridge?: string;
|
||||
};
|
||||
|
||||
export type ValidBuyWithCryptoStatus = Exclude<
|
||||
BuyWithCryptoStatus,
|
||||
{ status: "NOT_FOUND" }
|
||||
>;
|
||||
|
||||
/**
|
||||
* Gets the status of a buy with crypto transaction
|
||||
@@ -86,7 +83,7 @@ export type BuyWithCryptoStatus = {
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* import { sendTransaction, prepareTransaction } from "thirdweb";
|
||||
* import { sendTransaction } from "thirdweb";
|
||||
* import { getBuyWithCryptoStatus, getBuyWithCryptoQuote } from "thirdweb/pay";
|
||||
*
|
||||
* // get a quote between two tokens
|
||||
@@ -94,23 +91,26 @@ export type BuyWithCryptoStatus = {
|
||||
*
|
||||
* // if approval is required, send the approval transaction
|
||||
* if (quote.approval) {
|
||||
* const preparedApproval = prepareTransaction(quote.approval);
|
||||
* await sendTransaction({
|
||||
* transaction,
|
||||
* wallet,
|
||||
* const txResult = await sendTransaction({
|
||||
* transaction: quote.approval,
|
||||
* account: account, // account from connected wallet
|
||||
* });
|
||||
*
|
||||
* await waitForReceipt(txResult);
|
||||
* }
|
||||
*
|
||||
* // send the quoted transaction
|
||||
* const preparedTransaction = prepareTransaction(quote.transactionRequest);
|
||||
* const transactionResult = await sendTransaction({
|
||||
* transaction,
|
||||
* wallet,
|
||||
* const swapTxResult = await sendTransaction({
|
||||
* transaction: quote.transactionRequest,
|
||||
* account: account, // account from connected wallet
|
||||
* });
|
||||
*
|
||||
* await waitForReceipt(swapTxResult);
|
||||
*
|
||||
* // keep polling the status of the quoted transaction until it returns a success or failure status
|
||||
* const status = await getBuyWithCryptoStatus({
|
||||
* client,
|
||||
* transactionHash: transactionResult.transactionHash,
|
||||
* transactionHash: swapTxResult.transactionHash,
|
||||
* }});
|
||||
* ```
|
||||
* @returns Object of type [`BuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoStatus)
|
||||
@@ -130,7 +130,7 @@ export async function getBuyWithCryptoStatus(
|
||||
|
||||
const response = await getClientFetch(buyWithCryptoTransaction.client)(url);
|
||||
|
||||
// Assuming the response directly matches the SwapResponse interface
|
||||
// Assuming the response directly matches the BuyWithCryptoStatus interface
|
||||
if (!response.ok) {
|
||||
response.body?.cancel();
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
@@ -1,31 +0,0 @@
|
||||
import { getThirdwebDomains } from "../../../utils/domains.js";
|
||||
|
||||
/**
|
||||
* Constructs the endpoint to get the status of a quote.
|
||||
* @param client - The Thirdweb client containing the baseUrl config
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoStatusUrl = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/status/v1`;
|
||||
/**
|
||||
* Constructs the endpoint to get a pay quote.
|
||||
* @param client - The Thirdweb client containing the baseUrl config
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoQuoteEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/quote/v1`;
|
||||
|
||||
/**
|
||||
* Constructs the endpoint to get a wallet address swap history.
|
||||
* @param client - The Thirdweb client containing the baseUrl config
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoHistoryEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/history/v1`;
|
||||
|
||||
/**
|
||||
* Constructs the endpoint to get the pay endpoint
|
||||
* @internal
|
||||
*/
|
||||
export const getPayChainsEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/chains`;
|
||||
@@ -0,0 +1,90 @@
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import { getPayBuyWithFiatHistoryEndpoint } from "../utils/definitions.js";
|
||||
import type { BuyWithFiatStatus } from "./getStatus.js";
|
||||
|
||||
/**
|
||||
* The parameters for [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function
|
||||
* @buyCrypto
|
||||
*/
|
||||
export type BuyWithFiatHistoryParams = {
|
||||
/**
|
||||
* A client is the entry point to the thirdweb SDK. It is required for all other actions.
|
||||
*
|
||||
* You can create a client using the `createThirdwebClient` function.
|
||||
* Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
/**
|
||||
* The address of the wallet to get the wallet history for
|
||||
*/
|
||||
walletAddress: string;
|
||||
/**
|
||||
* The number of results to return in a single page. The default value is `10`.
|
||||
*/
|
||||
count: number;
|
||||
/**
|
||||
* index of the first result to return. The default value is `0`.
|
||||
*
|
||||
* If you want to start the list from nth item, you can set the start value to (n-1).
|
||||
*/
|
||||
start: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* The results for [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function
|
||||
* @buyFiat
|
||||
*/
|
||||
export type BuyWithFiatHistoryData = {
|
||||
page: BuyWithFiatStatus[];
|
||||
hasNextPage: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the "Buy with fiat" transaction history for a given wallet address
|
||||
* @param params Object of type [`BuyWithFiatHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryParams)
|
||||
* @example
|
||||
*
|
||||
* ```ts
|
||||
* import { createThirdwebClient } from "thirdweb";
|
||||
* import { getBuyWithFiatHistory } from "thirdweb/pay";
|
||||
*
|
||||
* const client = createThirdwebClient({ clientId: "..." });
|
||||
*
|
||||
* // get the 10 latest "Buy with fiat" transactions dony by the wallet
|
||||
* const history = await getBuyWithFiatHistory({
|
||||
* client: client,
|
||||
* walletAddress: '0x...',
|
||||
* start: 0,
|
||||
* count: 10,
|
||||
* })
|
||||
* ```
|
||||
* @returns Object of type [`BuyWithFiatHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryData)
|
||||
* @buyFiat
|
||||
*/
|
||||
export async function getBuyWithFiatHistory(
|
||||
params: BuyWithFiatHistoryParams,
|
||||
): Promise<BuyWithFiatHistoryData> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.append("walletAddress", params.walletAddress);
|
||||
queryParams.append("start", params.start.toString());
|
||||
queryParams.append("count", params.count.toString());
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const url = `${getPayBuyWithFiatHistoryEndpoint()}?${queryString}`;
|
||||
|
||||
const response = await getClientFetch(params.client)(url);
|
||||
|
||||
// Assuming the response directly matches the BuyWithFiatStatus response interface
|
||||
if (!response.ok) {
|
||||
response.body?.cancel();
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data: BuyWithFiatHistoryData = (await response.json()).result;
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw new Error(`Fetch failed: ${error}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import {
|
||||
type BuyWithCryptoQuote,
|
||||
getBuyWithCryptoQuote,
|
||||
} from "../buyWithCrypto/getQuote.js";
|
||||
import type { BuyWithFiatStatus } from "./getStatus.js";
|
||||
|
||||
/**
|
||||
* The parameters for [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function
|
||||
*/
|
||||
export type GetPostOnRampQuoteParams = {
|
||||
/**
|
||||
* A client is the entry point to the thirdweb SDK. It is required for all other actions.
|
||||
*
|
||||
* You can create a client using the `createThirdwebClient` function.
|
||||
* Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
/**
|
||||
* The "Buy with fiat" transaction status object returned by [`getBuyWithFiatStatus`](https://portal.thirdweb.com/typescript/v5/getBuyWithFiatStatus) function
|
||||
*/
|
||||
buyWithFiatStatus: BuyWithFiatStatus;
|
||||
};
|
||||
|
||||
/**
|
||||
* When buying a token with fiat currency - It only involes doing on-ramp if the on-ramp provider supports buying the given destination token directly.
|
||||
*
|
||||
* If the on-ramp provider does not support buying the destination token directly, user can be sent an intermediate token with fiat currency from the on-ramp provider which
|
||||
* can be swapped to destination token onchain.
|
||||
*
|
||||
* `getPostOnRampQuote` function is used to get the quote for swapping the on-ramp token to destination token.
|
||||
*
|
||||
* When you get a "Buy with Fiat" status of type "CRYPTO_SWAP_REQUIRED" from the [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function,
|
||||
* you can use `getPostOnRampQuote` function to get the quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for swapping the on-ramp token to destination token
|
||||
*
|
||||
* Once you have the quote, you can start the Swap process by following the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation.
|
||||
*
|
||||
* @param params - object of type [`GetPostOnRampQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetPostOnRampQuoteParams)
|
||||
* @returns Object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
|
||||
* @example
|
||||
* ```ts
|
||||
* import { getPostOnRampQuote, getBuyWithFiatStatus } from "thirdweb/pay";
|
||||
*
|
||||
* // previous steps
|
||||
* const fiatQuote = await getBuyWithFiatQuote(fiatQuoteParams);
|
||||
* window.open(fiatQuote.onRampLink, "_blank");
|
||||
* const buyWithFiatStatus = await getBuyWithFiatStatus({ client, intentId }); // keep calling this until status is "settled" state
|
||||
*
|
||||
* // when a swap is required after onramp
|
||||
* if (buyWithFiatStatus.status === "CRYPTO_SWAP_REQUIRED") {
|
||||
* const buyWithCryptoQuote = await getPostOnRampQuote({
|
||||
* client,
|
||||
* buyWithFiatStatus
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export async function getPostOnRampQuote({
|
||||
client,
|
||||
buyWithFiatStatus,
|
||||
}: GetPostOnRampQuoteParams): Promise<BuyWithCryptoQuote> {
|
||||
if (buyWithFiatStatus.status === "NOT_FOUND") {
|
||||
throw new Error("Invalid buyWithFiatStatus");
|
||||
}
|
||||
|
||||
return getBuyWithCryptoQuote({
|
||||
client,
|
||||
intentId: buyWithFiatStatus.intentId,
|
||||
fromAddress: buyWithFiatStatus.toAddress,
|
||||
fromChainId: buyWithFiatStatus.quote.onRampToken.chainId,
|
||||
fromTokenAddress: buyWithFiatStatus.quote.onRampToken.tokenAddress,
|
||||
toChainId: buyWithFiatStatus.quote.toToken.chainId,
|
||||
toTokenAddress: buyWithFiatStatus.quote.toToken.tokenAddress,
|
||||
toAmount: buyWithFiatStatus.quote.estimatedToTokenAmount,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import { getPayBuyWithFiatQuoteEndpoint } from "../utils/definitions.js";
|
||||
|
||||
/**
|
||||
* Parameters for [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
|
||||
*/
|
||||
export type GetBuyWithFiatQuoteParams = {
|
||||
/**
|
||||
* A client is the entry point to the thirdweb SDK. It is required for all other actions.
|
||||
*
|
||||
* You can create a client using the `createThirdwebClient` function.
|
||||
* Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
|
||||
/**
|
||||
* The address of the wallet to which the tokens will be sent.
|
||||
*/
|
||||
toAddress: string;
|
||||
|
||||
/**
|
||||
* Chain id of the token to buy.
|
||||
*/
|
||||
toChainId: number;
|
||||
|
||||
/**
|
||||
* Token address of the token to buy.
|
||||
*/
|
||||
toTokenAddress: string;
|
||||
|
||||
/**
|
||||
* Symbol of the fiat currency to buy the token with.
|
||||
*
|
||||
* Currently, only `USD` is supported.
|
||||
*/
|
||||
fromCurrencySymbol: "USD";
|
||||
|
||||
/**
|
||||
* The maximum slippage in basis points (bps) allowed for the transaction.
|
||||
* For example, if you want to allow a maximum slippage of 0.5%, you should specify `50` bps.
|
||||
*/
|
||||
maxSlippageBPS?: number;
|
||||
|
||||
/**
|
||||
* The amount of fiat currency to spend to buy the token.
|
||||
* This is useful if you want to buy whatever amount of token you can get for a certain amount of fiat currency.
|
||||
*
|
||||
* If you want a certain amount of token, you can provide `toAmount` instead of `fromAmount`.
|
||||
*/
|
||||
fromAmount?: string;
|
||||
|
||||
/**
|
||||
* The amount of token to buy
|
||||
* This is useful if you want to get a certain amount of token.
|
||||
*
|
||||
* If you want to buy however much token you can get for a certain amount of fiat currency, you can provide `fromAmount` instead of `toAmount`.
|
||||
*/
|
||||
toAmount?: string;
|
||||
|
||||
/**
|
||||
* Whether to use on-ramp provider in test mode for testing purpose or not.
|
||||
*
|
||||
* Defaults to `false`
|
||||
*/
|
||||
isTestMode?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* The response object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
|
||||
*
|
||||
* This includes various information for buying a token using a fiat currency:
|
||||
* - on-ramp provider UI link
|
||||
* - The estimated time for the transaction to complete.
|
||||
* - The on-ramp and destination token information.
|
||||
* - Processing fees
|
||||
*/
|
||||
export type BuyWithFiatQuote = {
|
||||
/**
|
||||
* Estimated time for the transaction to complete in seconds.
|
||||
*/
|
||||
estimatedDurationSeconds: number;
|
||||
/**
|
||||
* Minimum amount of token that is expected to be received in units.
|
||||
*/
|
||||
estimatedToAmountMin: string;
|
||||
/**
|
||||
* Minimum amount of token that is expected to be received in wei.
|
||||
*/
|
||||
estimatedToAmountMinWei: string;
|
||||
/**
|
||||
* Amount of token that is expected to be received in units.
|
||||
*
|
||||
* (estimatedToAmountMinWei - maxSlippageWei)
|
||||
*/
|
||||
toAmountMinWei: string;
|
||||
/**
|
||||
* Amount of token that is expected to be received in wei.
|
||||
*
|
||||
* (estimatedToAmountMin - maxSlippageWei)
|
||||
*/
|
||||
toAmountMin: string;
|
||||
/**
|
||||
* fiat currency used to buy the token - excluding the fees.
|
||||
*/
|
||||
fromCurrency: {
|
||||
amount: string;
|
||||
amountUnits: string;
|
||||
decimals: number;
|
||||
currencySymbol: string;
|
||||
};
|
||||
/**
|
||||
* Fiat currency used to buy the token - including the fees.
|
||||
*/
|
||||
fromCurrencyWithFees: {
|
||||
amount: string;
|
||||
amountUnits: string;
|
||||
decimals: number;
|
||||
currencySymbol: string;
|
||||
};
|
||||
/**
|
||||
* Token information for the desired token. (token the user wants to buy)
|
||||
*/
|
||||
toToken: {
|
||||
symbol?: string | undefined;
|
||||
priceUSDCents?: number | undefined;
|
||||
name?: string | undefined;
|
||||
chainId: number;
|
||||
tokenAddress: string;
|
||||
decimals: number;
|
||||
};
|
||||
/**
|
||||
* Address of the wallet to which the tokens will be sent.
|
||||
*/
|
||||
toAddress: string;
|
||||
/**
|
||||
* The maximum slippage in basis points (bps) allowed for the transaction.
|
||||
*/
|
||||
maxSlippageBPS: number;
|
||||
/**
|
||||
* Id of transaction
|
||||
*/
|
||||
intentId: string;
|
||||
/**
|
||||
* Array of processing fees for the transaction.
|
||||
*
|
||||
* This includes the processing fees for on-ramp and swap (if required).
|
||||
*/
|
||||
processingFees: {
|
||||
amount: string;
|
||||
amountUnits: string;
|
||||
decimals: number;
|
||||
currencySymbol: string;
|
||||
feeType: "ON_RAMP" | "NETWORK";
|
||||
}[];
|
||||
/**
|
||||
* Token that will be sent to the user's wallet address by the on-ramp provider.
|
||||
*
|
||||
* If the token is same as `toToken` - the user can directly buy the token from the on-ramp provider.
|
||||
* If not, the user will receive this token and a swap is required to convert it `toToken`.
|
||||
*/
|
||||
onRampToken: {
|
||||
amount: string;
|
||||
amountWei: string;
|
||||
amountUSDCents: number;
|
||||
token: {
|
||||
chainId: number;
|
||||
decimals: number;
|
||||
name: string;
|
||||
priceUSDCents: number;
|
||||
symbol: string;
|
||||
tokenAddress: string;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Link to the on-ramp provider UI that will prompt the user to buy the token with fiat currency.
|
||||
*
|
||||
* This link should be opened in a new tab.
|
||||
* @example
|
||||
* ```ts
|
||||
* window.open(quote.onRampLink, "_blank");
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
onRampLink: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a quote of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) to buy given token with fiat currency.
|
||||
* This quote contains the information about the swap such as token amounts, processing fees, estimated time etc.
|
||||
*
|
||||
* ### Rendering the On-Ramp provider UI
|
||||
* Once you have the `quote`, you can open the `quote.onRampLink` in a new tab - This will prompt the user to buy the token with fiat currency
|
||||
*
|
||||
* ### Determining the steps required
|
||||
* If `quote.onRampToken.token` is same as `quote.toToken` ( same chain + same token address ) - This means that the token can be directly bought from the on-ramp provider.
|
||||
* But if they are different, On-ramp provider will send the `quote.onRampToken` to the user's wallet address and a swap is required to swap it to the desired token onchain.
|
||||
*
|
||||
* You can use the [`isSwapRequiredPostOnramp`](https://portal.thirdweb.com/references/typescript/v5/isSwapRequiredPostOnramp) utility function to check if a swap is required after the on-ramp is done.
|
||||
*
|
||||
* ### Polling for the status
|
||||
* Once you open the `quote.onRampLink` in a new tab, you can start polling for the status using [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) to get the status of the transaction.
|
||||
*
|
||||
* `getBuyWithFiatStatus` returns a status object of type [`BuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatStatus).
|
||||
*
|
||||
* - If no swap is required - the status will become `"ON_RAMP_TRANSFER_COMPLETED"` once the on-ramp provider has sent the desired token to the user's wallet address. Once you receive this status, the process is complete.
|
||||
* - If a swap is required - the status will become `"CRYPTO_SWAP_REQUIRED"` once the on-ramp provider has sent the tokens to the user's wallet address. Once you receive this status, you need to start the swap process.
|
||||
*
|
||||
* ### Swap Process
|
||||
* On receiving the `"CRYPTO_SWAP_REQUIRED"` status, you can use the [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function to get the quote for the swap of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
|
||||
*
|
||||
* Once you have this quote - You can follow the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation to perform the swap.
|
||||
*
|
||||
* @param params - object of type [`GetBuyWithFiatQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatQuoteParams)
|
||||
* @returns Object of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
|
||||
* @example
|
||||
* Get a quote for buying 10 USDC on polygon chain (chainId: 137) with USD fiat currency:
|
||||
*
|
||||
* ```ts
|
||||
* import { getBuyWithFiatQuote } from "thirdweb/pay";
|
||||
*
|
||||
* const quote = await getBuyWithFiatQuote({
|
||||
* client: client, // thirdweb client
|
||||
* fromCurrencySymbol: "USD", // fiat currency symbol
|
||||
* toChainId: 137, // polygon chain id
|
||||
* toAmount: "10", // amount of USDC to buy
|
||||
* toTokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" // USDC token address in polygon chain
|
||||
* toAddress: "0x...", // user's wallet address
|
||||
* isTestMode: false, // whether to use onramp in test mode for testing purpose (defaults to false)
|
||||
* });
|
||||
*
|
||||
* window.open(quote.onRampLink, "_blank");
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export async function getBuyWithFiatQuote(
|
||||
params: GetBuyWithFiatQuoteParams,
|
||||
): Promise<BuyWithFiatQuote> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams({
|
||||
toAddress: params.toAddress,
|
||||
fromCurrencySymbol: params.fromCurrencySymbol,
|
||||
toChainId: params.toChainId.toString(),
|
||||
toTokenAddress: params.toTokenAddress.toLowerCase(),
|
||||
});
|
||||
|
||||
if (params.fromAmount) {
|
||||
queryParams.append("fromAmount", params.fromAmount);
|
||||
}
|
||||
|
||||
if (params.toAmount) {
|
||||
queryParams.append("toAmount", params.toAmount);
|
||||
}
|
||||
|
||||
if (params.maxSlippageBPS) {
|
||||
queryParams.append("maxSlippageBPS", params.maxSlippageBPS.toString());
|
||||
}
|
||||
|
||||
if (params.isTestMode) {
|
||||
queryParams.append("isTestMode", params.isTestMode.toString());
|
||||
}
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const url = `${getPayBuyWithFiatQuoteEndpoint()}?${queryString}`;
|
||||
|
||||
const response = await getClientFetch(params.client)(url);
|
||||
|
||||
// Assuming the response directly matches the SwapResponse interface
|
||||
if (!response.ok) {
|
||||
const errorObj = await response.json();
|
||||
if (errorObj && "error" in errorObj) {
|
||||
throw errorObj;
|
||||
}
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return (await response.json()).result;
|
||||
} catch (error) {
|
||||
console.error("Fetch error:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
import type { ThirdwebClient } from "../../client/client.js";
|
||||
import { getClientFetch } from "../../utils/fetch.js";
|
||||
import type {
|
||||
PayOnChainTransactionDetails,
|
||||
PayTokenInfo,
|
||||
} from "../utils/commonTypes.js";
|
||||
import { getPayBuyWithFiatStatusEndpoint } from "../utils/definitions.js";
|
||||
|
||||
/**
|
||||
* Parameters for the [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function
|
||||
*/
|
||||
export type GetBuyWithFiatStatusParams = {
|
||||
/**
|
||||
* A client is the entry point to the thirdweb SDK. It is required for all other actions.
|
||||
*
|
||||
* You can create a client using the `createThirdwebClient` function.
|
||||
* Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
/**
|
||||
* Intent ID of the "Buy with fiat" transaction. You can get the intent ID from the quote object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
|
||||
*/
|
||||
intentId: string;
|
||||
};
|
||||
|
||||
export type ValidBuyWithFiatStatus = Exclude<
|
||||
BuyWithFiatStatus,
|
||||
{ status: "NOT_FOUND" }
|
||||
>;
|
||||
|
||||
/**
|
||||
* The returned object from [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function
|
||||
*
|
||||
* If the in invalid intentId is provided, the object will have a status of "NOT_FOUND" and no other fields.
|
||||
*/
|
||||
export type BuyWithFiatStatus =
|
||||
| {
|
||||
status: "NOT_FOUND";
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* Intent ID of the "Buy with fiat" transaction. You can get the intent ID from the quote object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
|
||||
*/
|
||||
intentId: string;
|
||||
/**
|
||||
* The status of the transaction
|
||||
* - `NONE` - No status
|
||||
* - `PENDING_PAYMENT` - Payment is not done yet in the on-ramp provider
|
||||
* - `PAYMENT_FAILED` - Payment failed in the on-ramp provider
|
||||
* - `PENDING_ON_RAMP_TRANSFER` - Payment is done but the on-ramp provider is yet to transfer the tokens to the user's wallet
|
||||
* - `ON_RAMP_TRANSFER_IN_PROGRESS` - On-ramp provider is transferring the tokens to the user's wallet
|
||||
* - `ON_RAMP_TRANSFER_COMPLETED` - On-ramp provider has transferred the tokens to the user's wallet
|
||||
* - `ON_RAMP_TRANSFER_FAILED` - On-ramp provider failed to transfer the tokens to the user's wallet
|
||||
* - `CRYPTO_SWAP_REQUIRED` - On-ramp provider has sent the tokens to the user's wallet but a swap is required to convert it to the desired token
|
||||
* - `CRYPTO_SWAP_IN_PROGRESS` - Swap is in progress
|
||||
* - `CRYPTO_SWAP_COMPLETED` - Swap is completed and the user has received the desired token
|
||||
* - `CRYPTO_SWAP_FALLBACK` - Swap failed and the user has received a fallback token which is not the desired token
|
||||
*/
|
||||
status:
|
||||
| "NONE"
|
||||
| "PENDING_PAYMENT"
|
||||
| "PAYMENT_FAILED"
|
||||
| "PENDING_ON_RAMP_TRANSFER"
|
||||
| "ON_RAMP_TRANSFER_IN_PROGRESS"
|
||||
| "ON_RAMP_TRANSFER_COMPLETED"
|
||||
| "ON_RAMP_TRANSFER_FAILED"
|
||||
| "CRYPTO_SWAP_REQUIRED"
|
||||
| "CRYPTO_SWAP_COMPLETED"
|
||||
| "CRYPTO_SWAP_FALLBACK"
|
||||
| "CRYPTO_SWAP_IN_PROGRESS"
|
||||
| "CRYPTO_SWAP_FAILED";
|
||||
/**
|
||||
* The wallet address to which the tokens are sent to
|
||||
*/
|
||||
toAddress: string;
|
||||
/**
|
||||
* The quote object for the transaction
|
||||
*/
|
||||
quote: {
|
||||
estimatedOnRampAmount: string;
|
||||
estimatedOnRampAmountWei: string;
|
||||
|
||||
estimatedToTokenAmount: string;
|
||||
estimatedToTokenAmountWei: string;
|
||||
|
||||
fromCurrency: {
|
||||
amount: string;
|
||||
amountUnits: string;
|
||||
decimals: number;
|
||||
currencySymbol: string;
|
||||
};
|
||||
fromCurrencyWithFees: {
|
||||
amount: string;
|
||||
amountUnits: string;
|
||||
decimals: number;
|
||||
currencySymbol: string;
|
||||
};
|
||||
onRampToken: PayTokenInfo;
|
||||
toToken: PayTokenInfo;
|
||||
estimatedDurationSeconds?: number;
|
||||
createdAt: string;
|
||||
};
|
||||
/**
|
||||
* The on-ramp transaction details
|
||||
*
|
||||
* This field is only present when on-ramp transaction is completed or failed
|
||||
*/
|
||||
source?: PayOnChainTransactionDetails;
|
||||
/**
|
||||
* The destination transaction details
|
||||
*
|
||||
* This field is only present when swap transaction is completed or failed
|
||||
*/
|
||||
destination?: PayOnChainTransactionDetails;
|
||||
/**
|
||||
* Message indicating the reason for failure
|
||||
*/
|
||||
failureMessage?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Once you get a `quote` from [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote)
|
||||
* and open the `quote.onRampLink` in a new tab, you can start polling for the transaction status using `getBuyWithFiatStatus`
|
||||
*
|
||||
* You should keep calling this function at regular intervals while the status is in one of the pending states such as - "PENDING_PAYMENT", "PENDING_ON_RAMP_TRANSFER", "ON_RAMP_TRANSFER_IN_PROGRESS", "CRYPTO_SWAP_IN_PROGRESS" etc..
|
||||
*
|
||||
* If `quote.onRampToken` is same as `quote.toToken` (same chain + same token address) - This means that the token can be directly bought from the on-ramp provider.
|
||||
* But if they are different - On-ramp provider will send the `quote.onRampToken` to the user's wallet address and a swap is required to convert it to the desired token.
|
||||
* You can use the [`isSwapRequiredPostOnramp`](https://portal.thirdweb.com/references/typescript/v5/isSwapRequiredPostOnramp) utility function to check if a swap is required after the on-ramp is done.
|
||||
*
|
||||
* #### When no swap is required
|
||||
* If there is no swap required - the status will become `"ON_RAMP_TRANSFER_COMPLETED"` once the on-ramp provider has sent the tokens to the user's wallet address.
|
||||
* Once you receive this status, the process is complete.
|
||||
*
|
||||
* ### When a swap is required
|
||||
* If a swap is required - the status will become `"CRYPTO_SWAP_REQUIRED"` once the on-ramp provider has sent the tokens to the user's wallet address.
|
||||
* Once you receive this status, you need to start the swap process.
|
||||
*
|
||||
* On receiving the `"CRYPTO_SWAP_REQUIRED"` status, you can use the [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function to get the quote for the swap of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
|
||||
*
|
||||
* Once you have this quote - You can follow the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation to perform the swap.
|
||||
*
|
||||
* @param params - Object of type [`GetBuyWithFiatStatusParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatStatusParams)
|
||||
* @example
|
||||
* ```ts
|
||||
* // step 1 - get a quote
|
||||
* const fiatQuote = await getBuyWithFiatQuote(fiatQuoteParams)
|
||||
*
|
||||
* // step 2 - open the on-ramp provider UI
|
||||
* window.open(quote.onRampLink, "_blank");
|
||||
*
|
||||
* // step 3 - keep calling getBuyWithFiatStatus while the status is in one of the pending states
|
||||
* const fiatStatus = await getBuyWithFiatStatus({
|
||||
* client,
|
||||
* intentId: fiatQuote.intentId,
|
||||
* })
|
||||
*
|
||||
* // when the fiatStatus.status is "ON_RAMP_TRANSFER_COMPLETED" - the process is complete
|
||||
* // when the fiatStatus.status is "CRYPTO_SWAP_REQUIRED" - start the swap process
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export async function getBuyWithFiatStatus(
|
||||
params: GetBuyWithFiatStatusParams,
|
||||
): Promise<BuyWithFiatStatus> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams({
|
||||
intentId: params.intentId,
|
||||
});
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const url = `${getPayBuyWithFiatStatusEndpoint()}?${queryString}`;
|
||||
|
||||
const response = await getClientFetch(params.client)(url);
|
||||
|
||||
if (!response.ok) {
|
||||
response.body?.cancel();
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return (await response.json()).result;
|
||||
} catch (error) {
|
||||
console.error("Fetch error:", error);
|
||||
throw new Error(`Fetch failed: ${error}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { getAddress } from "../../utils/address.js";
|
||||
import type { BuyWithFiatQuote } from "./getQuote.js";
|
||||
|
||||
/**
|
||||
* Check if a Swap is required after on-ramp when buying a token with fiat currency.
|
||||
*
|
||||
* If `quote.toToken` and `quote.onRampToken` are the same (same token and chain),
|
||||
* it means on-ramp provider can directly send the desired token to the user's wallet and no swap is required.
|
||||
*
|
||||
* If `quote.toToken` and `quote.onRampToken` are different (different token or chain), A swap is required to swap the on-ramp token to the desired token.
|
||||
*
|
||||
* @param buyWithFiatQuote - The quote of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) returned
|
||||
* by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
|
||||
* @buyFiat
|
||||
*/
|
||||
export function isSwapRequiredPostOnramp(
|
||||
buyWithFiatQuote: Pick<BuyWithFiatQuote, "toToken" | "onRampToken">,
|
||||
) {
|
||||
const sameChain =
|
||||
buyWithFiatQuote.toToken.chainId ===
|
||||
buyWithFiatQuote.onRampToken.token.chainId;
|
||||
|
||||
const sameToken =
|
||||
getAddress(buyWithFiatQuote.toToken.tokenAddress) ===
|
||||
getAddress(buyWithFiatQuote.onRampToken.token.tokenAddress);
|
||||
|
||||
return !(sameChain && sameToken);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import type { ThirdwebClient } from "../client/client.js";
|
||||
import { getClientFetch } from "../utils/fetch.js";
|
||||
import type { BuyWithCryptoStatus } from "./buyWithCrypto/getStatus.js";
|
||||
import type { BuyWithFiatStatus } from "./buyWithFiat/getStatus.js";
|
||||
import { getPayBuyHistoryEndpoint } from "./utils/definitions.js";
|
||||
|
||||
/**
|
||||
* The parameters for [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyHistory) function
|
||||
*/
|
||||
export type BuyHistoryParams = {
|
||||
/**
|
||||
* A client is the entry point to the thirdweb SDK. It is required for all other actions.
|
||||
*
|
||||
* You can create a client using the `createThirdwebClient` function.
|
||||
* Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
|
||||
*/
|
||||
client: ThirdwebClient;
|
||||
/**
|
||||
* The wallet address to get the buy history for.
|
||||
*/
|
||||
walletAddress: string;
|
||||
/**
|
||||
* The number of results to return.
|
||||
*
|
||||
* The default value is `10`.
|
||||
*/
|
||||
count: number;
|
||||
/**
|
||||
* Index of the first result to return. The default value is `0`.
|
||||
*/
|
||||
start: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* The result for [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoHistory) function
|
||||
*
|
||||
* It includes both "Buy with Crypto" and "Buy with Fiat" transactions
|
||||
*/
|
||||
export type BuyHistoryData = {
|
||||
/**
|
||||
* The list of buy transactions.
|
||||
*/
|
||||
page: Array<
|
||||
| {
|
||||
buyWithFiatStatus: BuyWithFiatStatus;
|
||||
}
|
||||
| {
|
||||
buyWithCryptoStatus: BuyWithCryptoStatus;
|
||||
}
|
||||
>;
|
||||
/**
|
||||
* Whether there are more pages of results.
|
||||
*/
|
||||
hasNextPage: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Buy transaction history for a given wallet address.
|
||||
*
|
||||
* This includes both "Buy with Cryto" and "Buy with Fiat" transactions
|
||||
*
|
||||
* @param params Object of type [`BuyHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryParams)
|
||||
* @example
|
||||
* ```ts
|
||||
* import { createThirdwebClient } from "thirdweb";
|
||||
* import { getBuyHistory } from "thirdweb/pay";
|
||||
*
|
||||
* const client = createThirdwebClient({ clientId: "..." });
|
||||
*
|
||||
* const history = await getBuyHistory({
|
||||
* client,
|
||||
* walletAddress: "0x...",
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export async function getBuyHistory(
|
||||
params: BuyHistoryParams,
|
||||
): Promise<BuyHistoryData> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.append("walletAddress", params.walletAddress);
|
||||
queryParams.append("start", params.start.toString());
|
||||
queryParams.append("count", params.count.toString());
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const url = `${getPayBuyHistoryEndpoint()}?${queryString}`;
|
||||
|
||||
const response = await getClientFetch(params.client)(url);
|
||||
|
||||
// Assuming the response directly matches the SwapResponse interface
|
||||
if (!response.ok) {
|
||||
response.body?.cancel();
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data: BuyHistoryData = (await response.json()).result;
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw new Error(`Fetch failed: ${error}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
export type PayTokenInfo = {
|
||||
chainId: number;
|
||||
tokenAddress: string;
|
||||
decimals: number;
|
||||
priceUSDCents: number;
|
||||
name?: string;
|
||||
symbol?: string;
|
||||
};
|
||||
|
||||
export type PayOnChainTransactionDetails = {
|
||||
transactionHash: string;
|
||||
token: PayTokenInfo;
|
||||
amountWei: string;
|
||||
amount: string;
|
||||
amountUSDCents: number;
|
||||
completedAt?: string; // ISO DATE
|
||||
explorerLink?: string;
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import { getThirdwebDomains } from "../../utils/domains.js";
|
||||
|
||||
/**
|
||||
* Endpoint to get the status of a "Buy with Crypto" quote.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoStatusUrl = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/status/v1`;
|
||||
/**
|
||||
* Endpoint to get "Buy with Crypto" quote.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoQuoteEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/quote/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get a "Buy with Fiat" quote.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithFiatQuoteEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-fiat/quote/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get the status of a "Buy with Fiat" transaction status.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithFiatStatusEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-fiat/status/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get history of "Buy with Fiat" transactions for given wallet address.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithFiatHistoryEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-fiat/history/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get a "Buy with Crypto" transaction history for a given wallet address.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyWithCryptoHistoryEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/history/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get a list of supported destination chains and tokens for thirdweb pay.
|
||||
* @internal
|
||||
*/
|
||||
export const getPaySupportedDestinations = () =>
|
||||
`https://${getThirdwebDomains().pay}/destination-tokens/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get a list of supported source chains + tokens for thirdweb pay.
|
||||
* @internal
|
||||
*/
|
||||
export const getPaySupportedSources = () =>
|
||||
`https://${getThirdwebDomains().pay}/buy-with-crypto/source-tokens/v1`;
|
||||
|
||||
/**
|
||||
* Endpoint to get buy history for a given wallet address.
|
||||
* This includes both "Buy with Crypto" and "Buy with Fiat" transactions.
|
||||
* @internal
|
||||
*/
|
||||
export const getPayBuyHistoryEndpoint = () =>
|
||||
`https://${getThirdwebDomains().pay}/wallet/history/v1`;
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
type GetWalletBalanceResult,
|
||||
getWalletBalance,
|
||||
} from "../../../../wallets/utils/getWalletBalance.js";
|
||||
import { fetchSwapSupportedChains } from "../../../web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js";
|
||||
import { fetchBuySupportedDestinations } from "../../../web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js";
|
||||
import { useActiveAccount } from "../wallets/wallet-hooks.js";
|
||||
|
||||
type ShowModalData = {
|
||||
@@ -70,12 +70,10 @@ export function useSendTransactionCore(
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const swapSupportedChains = await fetchSwapSupportedChains(
|
||||
tx.client,
|
||||
);
|
||||
const destinations = await fetchBuySupportedDestinations(tx.client);
|
||||
|
||||
const isBuySupported = swapSupportedChains.find(
|
||||
(c) => c.id === tx.chain.id,
|
||||
const isBuySupported = destinations.find(
|
||||
(c) => c.chain.id === tx.chain.id,
|
||||
);
|
||||
|
||||
// buy not supported, can't show modal - send tx directly
|
||||
@@ -125,9 +123,8 @@ export function useSendTransactionCore(
|
||||
}
|
||||
|
||||
export async function getTotalTxCostForBuy(tx: PreparedTransaction) {
|
||||
// Must pass 0 otherwise it will throw on some chains
|
||||
const gasCost = await estimateGasCost({
|
||||
transaction: { ...tx, value: 0n },
|
||||
transaction: tx,
|
||||
});
|
||||
|
||||
const bufferCost = gasCost.wei / 10n;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { Chain } from "../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../client/client.js";
|
||||
import { getContract } from "../../../../contract/contract.js";
|
||||
|
||||
type GetTokenInfoOptions = {
|
||||
client: ThirdwebClient;
|
||||
chain: Chain;
|
||||
tokenAddress?: string;
|
||||
};
|
||||
|
||||
type GetTokenInfoResult = {
|
||||
name: string;
|
||||
symbol: string;
|
||||
decimals: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useTokenInfo(options: GetTokenInfoOptions) {
|
||||
const { chain, tokenAddress, client } = options;
|
||||
return useQuery({
|
||||
queryKey: ["tokenInfo", chain?.id || -1, { tokenAddress }] as const,
|
||||
queryFn: async () => {
|
||||
// erc20 case
|
||||
if (tokenAddress) {
|
||||
const { getCurrencyMetadata } = await import(
|
||||
"../../../../extensions/erc20/read/getCurrencyMetadata.js"
|
||||
);
|
||||
const result: GetTokenInfoResult = await getCurrencyMetadata({
|
||||
contract: getContract({ client, chain, address: tokenAddress }),
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const { getChainDecimals, getChainNativeCurrencyName, getChainSymbol } =
|
||||
await import("../../../../chains/utils.js");
|
||||
|
||||
const [nativeSymbol, nativeDecimals, nativeName] = await Promise.all([
|
||||
getChainSymbol(chain),
|
||||
getChainDecimals(chain),
|
||||
getChainNativeCurrencyName(chain),
|
||||
]);
|
||||
|
||||
const result: GetTokenInfoResult = {
|
||||
decimals: nativeDecimals,
|
||||
symbol: nativeSymbol,
|
||||
name: nativeName,
|
||||
};
|
||||
|
||||
return result;
|
||||
},
|
||||
enabled: !!chain && !!client,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
type UseQueryOptions,
|
||||
type UseQueryResult,
|
||||
useQuery,
|
||||
} from "@tanstack/react-query";
|
||||
import {
|
||||
type BuyHistoryData,
|
||||
type BuyHistoryParams,
|
||||
getBuyHistory,
|
||||
} from "../../../../pay/getBuyHistory.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type BuyHistoryQueryOptions = Omit<
|
||||
UseQueryOptions<BuyHistoryData>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Hook to get the history of Buy transactions for a given wallet - This includes both "buy with crypto" and "buy with fiat" transactions.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyHistory) function.
|
||||
* You can also use that function directly
|
||||
*
|
||||
* @param params - object of type [`BuyHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryParams)
|
||||
* @param queryParams - options to configure the react query
|
||||
* @returns A React Query object which contains the data of type [`BuyHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryData)
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useBuyHistory } from "thirdweb/react";
|
||||
*
|
||||
* function Component() {
|
||||
* const buyHistoryQuery = useBuyHistory(params);
|
||||
* return <div> ... </div>
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useBuyHistory(
|
||||
params?: BuyHistoryParams,
|
||||
queryParams?: BuyHistoryQueryOptions,
|
||||
): UseQueryResult<BuyHistoryData> {
|
||||
return useQuery({
|
||||
...queryParams,
|
||||
queryKey: ["getBuyHistory", params],
|
||||
queryFn: () => {
|
||||
if (!params) {
|
||||
throw new Error("params are required");
|
||||
}
|
||||
return getBuyHistory(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
});
|
||||
}
|
||||
@@ -7,20 +7,22 @@ import {
|
||||
type BuyWithCryptoHistoryData,
|
||||
type BuyWithCryptoHistoryParams,
|
||||
getBuyWithCryptoHistory,
|
||||
} from "../../../../pay/buyWithCrypto/actions/getHistory.js";
|
||||
} from "../../../../pay/buyWithCrypto/getHistory.js";
|
||||
|
||||
export type BuyWithCryptoHistoryQueryParams = BuyWithCryptoHistoryParams;
|
||||
export type BuyWithCryptoQuoteQueryOptions = Omit<
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type BuyWithCryptoHistoryQueryOptions = Omit<
|
||||
UseQueryOptions<BuyWithCryptoHistoryData>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Hook to get the history of purchases a given wallet has performed.
|
||||
* Hook to get the "Buy with crypto" transaction history for a given wallet address.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithCryptoHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoHistory) function.
|
||||
* You can also use that function directly
|
||||
* @param buyWithCryptoHistoryParams - object of type [`BuyWithCryptoHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryParams)
|
||||
* @param params - object of type [`BuyWithCryptoHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryParams)
|
||||
* @param queryParams - options to configure the react query
|
||||
* @returns A React Query object which contains the data of type [`BuyWithCryptoHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryData)
|
||||
* @example
|
||||
@@ -29,31 +31,24 @@ export type BuyWithCryptoQuoteQueryOptions = Omit<
|
||||
*
|
||||
* function Component() {
|
||||
* const buyWithCryptoHistory = useBuyWithCryptoHistory(params);
|
||||
* return <pre>{JSON.stringify(buyWithCryptoHistory.data, null, 2)}</pre>
|
||||
* return <div> ... </div>
|
||||
* }
|
||||
* ```
|
||||
* @buyCrypto
|
||||
*/
|
||||
export function useBuyWithCryptoHistory(
|
||||
buyWithCryptoHistoryParams?: BuyWithCryptoHistoryQueryParams,
|
||||
queryParams?: BuyWithCryptoQuoteQueryOptions,
|
||||
params?: BuyWithCryptoHistoryParams,
|
||||
queryParams?: BuyWithCryptoHistoryQueryOptions,
|
||||
): UseQueryResult<BuyWithCryptoHistoryData> {
|
||||
return useQuery({
|
||||
...queryParams,
|
||||
|
||||
queryKey: ["buyWithCryptoHistory", buyWithCryptoHistoryParams],
|
||||
queryKey: ["getBuyWithCryptoHistory", params],
|
||||
queryFn: () => {
|
||||
if (!buyWithCryptoHistoryParams) {
|
||||
if (!params) {
|
||||
throw new Error("Swap params are required");
|
||||
}
|
||||
if (!buyWithCryptoHistoryParams?.client) {
|
||||
throw new Error("Client is required");
|
||||
}
|
||||
return getBuyWithCryptoHistory({
|
||||
...buyWithCryptoHistoryParams,
|
||||
client: buyWithCryptoHistoryParams.client,
|
||||
});
|
||||
return getBuyWithCryptoHistory(params);
|
||||
},
|
||||
enabled: !!buyWithCryptoHistoryParams,
|
||||
enabled: !!params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,15 +7,20 @@ import {
|
||||
type BuyWithCryptoQuote,
|
||||
type GetBuyWithCryptoQuoteParams,
|
||||
getBuyWithCryptoQuote,
|
||||
} from "../../../../pay/buyWithCrypto/actions/getQuote.js";
|
||||
} from "../../../../pay/buyWithCrypto/getQuote.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type BuyWithCryptoQuoteQueryOptions = Omit<
|
||||
UseQueryOptions<BuyWithCryptoQuote>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
|
||||
|
||||
/**
|
||||
* Hook to get a quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for buying tokens with crypto.
|
||||
* Hook to get a price quote for performing a "Buy with crypto" transaction that allows users to buy a token with another token - aka a swap.
|
||||
*
|
||||
* The price quote is an object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
|
||||
* This quote contains the information about the purchase such as token amounts, processing fees, estimated time etc.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) function.
|
||||
@@ -23,16 +28,16 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
|
||||
*
|
||||
* Once you have the quote, you can use the [`useSendTransaction`](https://portal.thirdweb.com/references/typescript/v5/useSendTransaction) function to send the purchase
|
||||
* and [`useBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithCryptoStatus) function to get the status of the swap transaction.
|
||||
* @param buyWithCryptoParams - object of type [`BuyWithCryptoQuoteQueryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuoteQueryParams)
|
||||
* @param params - object of type [`BuyWithCryptoQuoteQueryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuoteQueryParams)
|
||||
* @param queryParams - options to configure the react query
|
||||
* @returns A React Query object which contains the data of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote)
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams } from "thirdweb/react";
|
||||
* import { useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams, useActiveAccount } from "thirdweb/react";
|
||||
* import { sendTransaction } from 'thirdweb';
|
||||
*
|
||||
* function Component() {
|
||||
* const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(swapParams);
|
||||
* const sendTransactionMutation = useSendTransaction();
|
||||
* const [buyTxHash, setBuyTxHash] = useState<BuyWithCryptoStatusQueryParams | undefined>();
|
||||
* const buyWithCryptoStatusQuery = useBuyWithCryptoStatus(buyTxHash ? {
|
||||
* client,
|
||||
@@ -40,16 +45,23 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
|
||||
* }: undefined);
|
||||
*
|
||||
* async function handleBuyWithCrypto() {
|
||||
* const account = useActiveAccount();
|
||||
*
|
||||
* // if approval is required
|
||||
* if (buyWithCryptoQuoteQuery.data.approval) {
|
||||
* const approveTx = await sendTransactionMutation.mutateAsync(swapQuote.data.approval);
|
||||
* const approveTx = await sendTransaction({
|
||||
* transaction: swapQuote.data.approval,
|
||||
* account: account,
|
||||
* });
|
||||
* await waitForApproval(approveTx);
|
||||
* }
|
||||
*
|
||||
* // send the transaction to buy crypto
|
||||
* // this promise is resolved when user confirms the transaction in the wallet and the transaction is sent to the blockchain
|
||||
* const buyTx = await sendTransactionMutation.mutateAsync(swapQuote.data.transactionRequest);
|
||||
* const buyTx = await sendTransaction({
|
||||
* transaction: swapQuote.data.transactionRequest,
|
||||
* account: account,
|
||||
* });
|
||||
* await waitForApproval(buyTx);
|
||||
*
|
||||
* // set buyTx.transactionHash to poll the status of the swap transaction
|
||||
@@ -62,26 +74,30 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
|
||||
* @buyCrypto
|
||||
*/
|
||||
export function useBuyWithCryptoQuote(
|
||||
buyWithCryptoParams?: BuyWithCryptoQuoteQueryParams,
|
||||
params?: GetBuyWithCryptoQuoteParams,
|
||||
queryParams?: BuyWithCryptoQuoteQueryOptions,
|
||||
): UseQueryResult<BuyWithCryptoQuote> {
|
||||
return useQuery({
|
||||
...queryParams,
|
||||
|
||||
queryKey: ["buyWithCryptoQuote", buyWithCryptoParams],
|
||||
queryKey: ["buyWithCryptoQuote", params],
|
||||
queryFn: () => {
|
||||
if (!buyWithCryptoParams) {
|
||||
if (!params) {
|
||||
throw new Error("Swap params are required");
|
||||
}
|
||||
if (!buyWithCryptoParams?.client) {
|
||||
throw new Error("Client is required in swap params");
|
||||
}
|
||||
return getBuyWithCryptoQuote({
|
||||
// typescript limitation with discriminated unions are collapsed
|
||||
...(buyWithCryptoParams as GetBuyWithCryptoQuoteParams),
|
||||
client: buyWithCryptoParams.client,
|
||||
});
|
||||
|
||||
return getBuyWithCryptoQuote(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
retry(failureCount, error) {
|
||||
if (failureCount > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (error.message.includes("Minimum purchase")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
enabled: !!buyWithCryptoParams,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,47 +1,48 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
type BuyWithCryptoStatus,
|
||||
type BuyWithCryptoTransaction,
|
||||
getBuyWithCryptoStatus,
|
||||
} from "../../../../pay/buyWithCrypto/actions/getStatus.js";
|
||||
|
||||
// TODO: use the estimate to vary the polling interval
|
||||
const DEFAULT_POLL_INTERVAL = 5000;
|
||||
|
||||
export type BuyWithCryptoStatusQueryParams = BuyWithCryptoTransaction;
|
||||
} from "../../../../pay/buyWithCrypto/getStatus.js";
|
||||
|
||||
/**
|
||||
* A hook to get a status of swap transaction.
|
||||
* A hook to get a status of a "Buy with crypto" transaction to determine if the transaction is completed, failed or pending.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoStatus) function.
|
||||
* You can also use that function directly.
|
||||
* @param buyWithCryptoStatusParams - object of type [`BuyWithCryptoTransaction`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoTransaction)
|
||||
* @param params - object of type [`BuyWithCryptoTransaction`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoTransaction)
|
||||
* @returns A react query object which contains the data of type [`BuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoStatus)
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams } from "thirdweb/react";
|
||||
* import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams, useActiveAccount } from "thirdweb/react";
|
||||
* import { sendTransaction } from 'thirdweb';
|
||||
*
|
||||
* function Component() {
|
||||
* const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(swapParams);
|
||||
* const sendTransactionMutation = useSendTransaction();
|
||||
* const [buyTxHash, setBuyTxHash] = useState<BuyWithCryptoStatusQueryParams | undefined>();
|
||||
* const buyWithCryptoStatusQuery = useBuyWithCryptoStatus(buyTxHash ? {
|
||||
* client,
|
||||
* transactionHash: buyTxHash,
|
||||
* }: undefined);
|
||||
* const account = useActiveAccount();
|
||||
*
|
||||
* async function handleBuyWithCrypto() {
|
||||
*
|
||||
* // if approval is required
|
||||
* if (buyWithCryptoQuoteQuery.data.approval) {
|
||||
* const approveTx = await sendTransactionMutation.mutateAsync(swapQuote.data.approval);
|
||||
* const approveTx = await sendTransaction({
|
||||
* account: account,
|
||||
* transaction: swapQuote.data.approval,
|
||||
* });
|
||||
* await waitForApproval(approveTx);
|
||||
* }
|
||||
*
|
||||
* // send the transaction to buy crypto
|
||||
* // this promise is resolved when user confirms the transaction in the wallet and the transaction is sent to the blockchain
|
||||
* const buyTx = await sendTransactionMutation.mutateAsync(swapQuote.data.transactionRequest);
|
||||
* const buyTx = await sendTransactionMutation.mutateAsync({
|
||||
* transaction: swapQuote.data.transactionRequest,
|
||||
* account: account,
|
||||
* });
|
||||
* await waitForApproval(buyTx);
|
||||
*
|
||||
* // set buyTx.transactionHash to poll the status of the swap transaction
|
||||
@@ -53,40 +54,17 @@ export type BuyWithCryptoStatusQueryParams = BuyWithCryptoTransaction;
|
||||
* ```
|
||||
* @buyCrypto
|
||||
*/
|
||||
export function useBuyWithCryptoStatus(
|
||||
buyWithCryptoStatusParams?: BuyWithCryptoStatusQueryParams,
|
||||
) {
|
||||
const [refetchInterval, setRefetchInterval] = useState<number>(
|
||||
DEFAULT_POLL_INTERVAL,
|
||||
);
|
||||
|
||||
export function useBuyWithCryptoStatus(params?: BuyWithCryptoTransaction) {
|
||||
return useQuery<BuyWithCryptoStatus, Error>({
|
||||
queryKey: [
|
||||
"swapStatus",
|
||||
buyWithCryptoStatusParams?.transactionHash,
|
||||
] as const,
|
||||
queryKey: ["getBuyWithCryptoStatus", params?.transactionHash] as const,
|
||||
queryFn: async () => {
|
||||
if (!buyWithCryptoStatusParams) {
|
||||
throw new Error("Missing swap status params");
|
||||
if (!params) {
|
||||
throw new Error("No params");
|
||||
}
|
||||
if (!buyWithCryptoStatusParams?.client) {
|
||||
throw new Error("Missing client in swap status params");
|
||||
}
|
||||
|
||||
const swapStatus_ = await getBuyWithCryptoStatus({
|
||||
...buyWithCryptoStatusParams,
|
||||
client: buyWithCryptoStatusParams.client,
|
||||
});
|
||||
if (
|
||||
swapStatus_.status === "COMPLETED" ||
|
||||
swapStatus_.status === "FAILED"
|
||||
) {
|
||||
setRefetchInterval(0);
|
||||
}
|
||||
return swapStatus_;
|
||||
return getBuyWithCryptoStatus(params);
|
||||
},
|
||||
enabled: !!buyWithCryptoStatusParams,
|
||||
refetchInterval: refetchInterval,
|
||||
enabled: !!params,
|
||||
refetchInterval: 5000,
|
||||
refetchIntervalInBackground: true,
|
||||
retry: true,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
type UseQueryOptions,
|
||||
type UseQueryResult,
|
||||
useQuery,
|
||||
} from "@tanstack/react-query";
|
||||
import {
|
||||
type BuyWithFiatHistoryData,
|
||||
type BuyWithFiatHistoryParams,
|
||||
getBuyWithFiatHistory,
|
||||
} from "../../../../pay/buyWithFiat/getHistory.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type BuyWithFiatHistoryQueryOptions = Omit<
|
||||
UseQueryOptions<BuyWithFiatHistoryData>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Hook to get the "Buy with Fiat" transaction history for a given wallet address.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function.
|
||||
* You can also use that function directly
|
||||
* @param params - object of type [`BuyWithFiatHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryParams)
|
||||
* @param queryParams - options to configure the react query
|
||||
* @returns A React Query object which contains the data of type [`BuyWithFiatHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryData)
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useBuyWithFiatHistory } from "thirdweb/react";
|
||||
*
|
||||
* function Component() {
|
||||
* const historyQuery = useBuyWithFiatHistory(params);
|
||||
* return <div> ... </div>
|
||||
* }
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export function useBuyWithFiatHistory(
|
||||
params?: BuyWithFiatHistoryParams,
|
||||
queryParams?: BuyWithFiatHistoryQueryOptions,
|
||||
): UseQueryResult<BuyWithFiatHistoryData> {
|
||||
return useQuery({
|
||||
...queryParams,
|
||||
queryKey: ["buyWithFiatHistory", params],
|
||||
queryFn: () => {
|
||||
if (!params) {
|
||||
throw new Error("params are required");
|
||||
}
|
||||
return getBuyWithFiatHistory(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
type UseQueryOptions,
|
||||
type UseQueryResult,
|
||||
useQuery,
|
||||
} from "@tanstack/react-query";
|
||||
import {
|
||||
type BuyWithFiatQuote,
|
||||
type GetBuyWithFiatQuoteParams,
|
||||
getBuyWithFiatQuote,
|
||||
} from "../../../../pay/buyWithFiat/getQuote.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type BuyWithFiatQuoteQueryOptions = Omit<
|
||||
UseQueryOptions<BuyWithFiatQuote>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Hook to get a price quote for performing a "Buy with Fiat" transaction that allows users to buy a token with fiat currency.
|
||||
*
|
||||
* The price quote is an object of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote).
|
||||
* This quote contains the information about the purchase such as token amounts, processing fees, estimated time etc.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
|
||||
* You can also use that function directly
|
||||
*
|
||||
* Once you have the `quote`, you can open a new window with `quote.onRampLink` to allow the user to buy the token with fiat currency.
|
||||
* and [`useBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithFiatStatus) function to start polling for the status of this transaction.
|
||||
*
|
||||
* @param params - object of type [`GetBuyWithFiatQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatQuoteParams)
|
||||
* @param queryParams - options to configure the react query
|
||||
* @returns A React Query object which contains the data of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote)
|
||||
* @example
|
||||
* ```ts
|
||||
* import { NATIVE_TOKEN_ADDRESS } from "thirdweb";
|
||||
* import { base } from "thirdweb/chains";
|
||||
* import { useBuyWithFiatQuote } from "thirdweb/react";
|
||||
*
|
||||
* // get a quote for buying 0.01 base native token with USD fiat currency
|
||||
* function Example() {
|
||||
* const quote = useBuyWithFiatQuote({
|
||||
* client: client, // thirdweb client
|
||||
* fromCurrencySymbol: "USD", // fiat currency symbol
|
||||
* toChainId: base.id, // base chain id
|
||||
* toAmount: "0.01", // amount of token to buy
|
||||
* toTokenAddress: NATIVE_TOKEN_ADDRESS, // native token
|
||||
* toAddress: "0x...", // user's wallet address
|
||||
* });
|
||||
*
|
||||
* return (
|
||||
* <div>
|
||||
* {quote.data && (
|
||||
* <a href={quote.data.onRampLink} target="_blank">
|
||||
* open onramp provider
|
||||
* </a>
|
||||
* )}
|
||||
* </div>
|
||||
* );
|
||||
* }
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export function useBuyWithFiatQuote(
|
||||
params?: GetBuyWithFiatQuoteParams,
|
||||
queryOptions?: BuyWithFiatQuoteQueryOptions,
|
||||
): UseQueryResult<BuyWithFiatQuote> {
|
||||
return useQuery({
|
||||
...queryOptions,
|
||||
queryKey: ["useBuyWithFiatQuote", params],
|
||||
queryFn: async () => {
|
||||
if (!params) {
|
||||
throw new Error("No params provided");
|
||||
}
|
||||
return getBuyWithFiatQuote(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
retry(failureCount, error) {
|
||||
if (failureCount > 3) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
if ((error as any).error.code === "MINIMUM_PURCHASE_AMOUNT") {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { type UseQueryResult, useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
type BuyWithFiatStatus,
|
||||
type GetBuyWithFiatStatusParams,
|
||||
getBuyWithFiatStatus,
|
||||
} from "../../../../pay/buyWithFiat/getStatus.js";
|
||||
|
||||
/**
|
||||
* A hook to get a status of a "Buy with Fiat" transaction to determine if the transaction is completed, failed or pending.
|
||||
*
|
||||
* This hook is a React Query wrapper of the [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoStatus) function.
|
||||
* You can also use that function directly.
|
||||
*
|
||||
* `useBuyWithFiatStatus` refetches the status using `getBuyWithFiatStatus` every 5 seconds.
|
||||
*
|
||||
* @param params - object of type [`GetBuyWithFiatStatusParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoTransaction)
|
||||
* @returns A react query object which contains the data of type [`BuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoStatus)
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useBuyWithFiatStatus } from "thirdweb/react";
|
||||
* import { client } from "./client";
|
||||
*
|
||||
* function Example() {
|
||||
* const fiatStatus = useBuyWithFiatStatus({
|
||||
* client: client, // thirdweb client
|
||||
* intentId: "....", // get the intentId from quote ( quote.intentId )
|
||||
* });
|
||||
*
|
||||
* console.log(fiatStatus.data);
|
||||
*
|
||||
* return <div>...</div>;
|
||||
* }
|
||||
* ```
|
||||
* @buyFiat
|
||||
*/
|
||||
export function useBuyWithFiatStatus(
|
||||
params?: GetBuyWithFiatStatusParams,
|
||||
): UseQueryResult<BuyWithFiatStatus> {
|
||||
return useQuery({
|
||||
queryKey: ["useBuyWithFiatStatus", params],
|
||||
queryFn: async () => {
|
||||
if (!params) {
|
||||
throw new Error("No params provided");
|
||||
}
|
||||
return getBuyWithFiatStatus(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
refetchInterval: 5000,
|
||||
refetchIntervalInBackground: true,
|
||||
retry: true,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
type UseQueryOptions,
|
||||
type UseQueryResult,
|
||||
useQuery,
|
||||
} from "@tanstack/react-query";
|
||||
import type { BuyWithCryptoQuote } from "../../../../pay/buyWithCrypto/getQuote.js";
|
||||
import {
|
||||
type GetPostOnRampQuoteParams,
|
||||
getPostOnRampQuote,
|
||||
} from "../../../../pay/buyWithFiat/getPostOnRampQuote.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type PostOnRampQuoteQueryOptions = Omit<
|
||||
UseQueryOptions<BuyWithCryptoQuote>,
|
||||
"queryFn" | "queryKey" | "enabled"
|
||||
>;
|
||||
|
||||
/**
|
||||
* When buying a token with fiat currency - It only involes doing on-ramp if the on-ramp provider supports buying the given destination token directly.
|
||||
*
|
||||
* If the on-ramp provider does not support buying the destination token directly, user can be sent an intermediate token with fiat currency from the on-ramp provider which
|
||||
* can be swapped to destination token onchain.
|
||||
*
|
||||
* `usePostOnRampQuote` hook is used to get the quote for swapping the on-ramp token to destination token.
|
||||
*
|
||||
* When you get a "Buy with Fiat" status of type `"CRYPTO_SWAP_REQUIRED"` from the [`useBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithFiatStatus) hook,
|
||||
* you can use `usePostOnRampQuote` hook to get the quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for swapping the on-ramp token to destination token to complete the step-2 of the process.
|
||||
*
|
||||
* Once you have the quote, you can start the Swap process by following the same steps as mentioned in the [`useBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithCryptoQuote) documentation.
|
||||
*
|
||||
* @param params - object of type [`GetPostOnRampQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetPostOnRampQuoteParams)
|
||||
* @returns Object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
|
||||
* @buyFiat
|
||||
*/
|
||||
export function usePostOnRampQuote(
|
||||
params?: GetPostOnRampQuoteParams,
|
||||
queryOptions?: PostOnRampQuoteQueryOptions,
|
||||
): UseQueryResult<BuyWithCryptoQuote> {
|
||||
return useQuery({
|
||||
...queryOptions,
|
||||
queryKey: ["getPostOnRampQuote", params],
|
||||
queryFn: async () => {
|
||||
if (!params) {
|
||||
throw new Error("No params provided");
|
||||
}
|
||||
return getPostOnRampQuote(params);
|
||||
},
|
||||
enabled: !!params,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { QueryClient } from "@tanstack/react-query";
|
||||
|
||||
export function invalidateWalletBalance(
|
||||
queryClient: QueryClient,
|
||||
chainId?: number,
|
||||
) {
|
||||
return queryClient.invalidateQueries({
|
||||
// invalidate any walletBalance queries for this chainId
|
||||
// TODO: add wallet address in here if we can get it somehow
|
||||
queryKey: ["walletBalance", chainId] as const,
|
||||
});
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { isBaseTransactionOptions } from "../../../transaction/types.js";
|
||||
import { isObjectWithKeys } from "../../../utils/type-guards.js";
|
||||
import { SetRootElementContext } from "./RootElementContext.js";
|
||||
import { invalidateWalletBalance } from "./invalidateWalletBalance.js";
|
||||
|
||||
/**
|
||||
* The ThirdwebProvider is component is a provider component that sets up the React Query client.
|
||||
@@ -58,14 +59,10 @@ export function ThirdwebProvider(props: React.PropsWithChildren) {
|
||||
variables.__contract?.address,
|
||||
] as const,
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
// invalidate any walletBalance queries for this chainId
|
||||
// TODO: add wallet address in here if we can get it somehow
|
||||
queryKey: [
|
||||
"walletBalance",
|
||||
variables.__contract?.chain.id,
|
||||
] as const,
|
||||
}),
|
||||
invalidateWalletBalance(
|
||||
queryClient,
|
||||
variables.__contract?.chain.id,
|
||||
),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { CheckCircledIcon } from "@radix-ui/react-icons";
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import type { ThirdwebClient } from "../../../client/client.js";
|
||||
import type { GaslessOptions } from "../../../transaction/actions/gasless/types.js";
|
||||
import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
|
||||
@@ -6,16 +7,20 @@ import type { Wallet } from "../../../wallets/interfaces/wallet.js";
|
||||
import { useSendTransactionCore } from "../../core/hooks/contract/useSendTransaction.js";
|
||||
import { useActiveWallet } from "../../core/hooks/wallets/wallet-hooks.js";
|
||||
import { SetRootElementContext } from "../../core/providers/RootElementContext.js";
|
||||
import {
|
||||
type SupportedTokens,
|
||||
defaultTokens,
|
||||
} from "../ui/ConnectWallet/defaultTokens.js";
|
||||
import type { PayUIOptions } from "../ui/ConnectWallet/ConnectButtonProps.js";
|
||||
import type { SupportedTokens } from "../ui/ConnectWallet/defaultTokens.js";
|
||||
import { AccentFailIcon } from "../ui/ConnectWallet/icons/AccentFailIcon.js";
|
||||
import { useConnectLocale } from "../ui/ConnectWallet/locale/getConnectLocale.js";
|
||||
import { BuyScreen } from "../ui/ConnectWallet/screens/Buy/SwapScreen.js";
|
||||
import { SwapTransactionsScreen } from "../ui/ConnectWallet/screens/SwapTransactionsScreen.js";
|
||||
import { LazyBuyScreen } from "../ui/ConnectWallet/screens/Buy/LazyBuyScreen.js";
|
||||
import { BuyTxHistory } from "../ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistory.js";
|
||||
import { Modal } from "../ui/components/Modal.js";
|
||||
import { Spacer } from "../ui/components/Spacer.js";
|
||||
import { Spinner } from "../ui/components/Spinner.js";
|
||||
import { Container, ModalHeader } from "../ui/components/basic.js";
|
||||
import { Button } from "../ui/components/buttons.js";
|
||||
import { Text } from "../ui/components/text.js";
|
||||
import { CustomThemeProvider } from "../ui/design-system/CustomThemeProvider.js";
|
||||
import type { Theme } from "../ui/design-system/index.js";
|
||||
import { type Theme, iconSize } from "../ui/design-system/index.js";
|
||||
import type { LocaleId } from "../ui/types.js";
|
||||
import { LoadingScreen } from "../wallets/shared/LoadingScreen.js";
|
||||
|
||||
@@ -44,6 +49,12 @@ export type SendTransactionPayModalConfig =
|
||||
locale?: LocaleId;
|
||||
supportedTokens?: SupportedTokens;
|
||||
theme?: Theme | "light" | "dark";
|
||||
buyWithCrypto?: false;
|
||||
buyWithFiat?:
|
||||
| false
|
||||
| {
|
||||
testMode?: boolean;
|
||||
};
|
||||
}
|
||||
| false;
|
||||
|
||||
@@ -52,26 +63,10 @@ export type SendTransactionPayModalConfig =
|
||||
*/
|
||||
export type SendTransactionConfig = {
|
||||
/**
|
||||
* Configuration for the "Pay Modal" that opens when the user doesn't have enough funds to send a transaction.
|
||||
* Set `payModal: false` to disable the "Pay Modal" popup
|
||||
*
|
||||
* This configuration object includes the following properties to configure the "Pay Modal" UI:
|
||||
*
|
||||
* ### `locale`
|
||||
* The language to use for the "Pay Modal" UI. Defaults to `"en_US"`.
|
||||
*
|
||||
* ### `supportedTokens`
|
||||
* An object of type [`SupportedTokens`](https://portal.thirdweb.com/references/typescript/v5/SupportedTokens) to configure the tokens to show for a chain.
|
||||
*
|
||||
* ### `theme`
|
||||
* The theme to use for the "Pay Modal" UI. Defaults to `"dark"`.
|
||||
*
|
||||
* It can be set to `"light"` or `"dark"` or an object of type [`Theme`](https://portal.thirdweb.com/references/typescript/v5/Theme) for a custom theme.
|
||||
*
|
||||
* Refer to [`lightTheme`](https://portal.thirdweb.com/references/typescript/v5/lightTheme)
|
||||
* or [`darkTheme`](https://portal.thirdweb.com/references/typescript/v5/darkTheme) helper functions to use the default light or dark theme and customize it.
|
||||
* Refer to [`SendTransactionPayModalConfig`](https://portal.thirdweb.com/references/typescript/v5/SendTransactionPayModalConfig) for more details.
|
||||
*/
|
||||
payModal?: SendTransactionPayModalConfig;
|
||||
|
||||
/**
|
||||
* Configuration for gasless transactions.
|
||||
* Refer to [`GaslessOptions`](https://portal.thirdweb.com/references/typescript/v5/GaslessOptions) for more details.
|
||||
@@ -133,11 +128,15 @@ export function useSendTransaction(config: SendTransactionConfig = {}) {
|
||||
}}
|
||||
client={data.tx.client}
|
||||
localeId={payModal?.locale || "en_US"}
|
||||
supportedTokens={payModal?.supportedTokens || defaultTokens}
|
||||
supportedTokens={payModal?.supportedTokens}
|
||||
theme={payModal?.theme || "dark"}
|
||||
txCostWei={data.totalCostWei}
|
||||
walletBalanceWei={data.walletBalance.value}
|
||||
nativeTokenSymbol={data.walletBalance.symbol}
|
||||
payOptions={{
|
||||
buyWithCrypto: payModal?.buyWithCrypto,
|
||||
buyWithFiat: payModal?.buyWithFiat,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
},
|
||||
@@ -150,12 +149,13 @@ type ModalProps = {
|
||||
onClose: () => void;
|
||||
client: ThirdwebClient;
|
||||
localeId: LocaleId;
|
||||
supportedTokens: SupportedTokens;
|
||||
supportedTokens?: SupportedTokens;
|
||||
theme: Theme | "light" | "dark";
|
||||
txCostWei: bigint;
|
||||
walletBalanceWei: bigint;
|
||||
nativeTokenSymbol: string;
|
||||
tx: PreparedTransaction;
|
||||
payOptions: PayUIOptions;
|
||||
};
|
||||
|
||||
function TxModal(props: ModalProps) {
|
||||
@@ -178,29 +178,38 @@ function TxModal(props: ModalProps) {
|
||||
|
||||
function ModalContent(props: ModalProps) {
|
||||
const localeQuery = useConnectLocale(props.localeId);
|
||||
const [screen, setScreen] = useState<"buy" | "tx-history">("buy");
|
||||
const [screen, setScreen] = useState<"buy" | "tx-history" | "execute-tx">(
|
||||
"buy",
|
||||
);
|
||||
|
||||
if (!localeQuery.data) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
||||
if (screen === "execute-tx") {
|
||||
return <ExecutingTxScreen tx={props.tx} closeModal={props.onClose} />;
|
||||
}
|
||||
|
||||
if (screen === "tx-history") {
|
||||
return (
|
||||
<SwapTransactionsScreen
|
||||
<BuyTxHistory
|
||||
client={props.client}
|
||||
onBack={() => {
|
||||
props.onClose();
|
||||
setScreen("buy");
|
||||
}}
|
||||
onDone={() => {
|
||||
setScreen("execute-tx");
|
||||
}}
|
||||
isBuyForTx={true}
|
||||
isEmbed={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BuyScreen
|
||||
<LazyBuyScreen
|
||||
isEmbed={false}
|
||||
client={props.client}
|
||||
onBack={() => {
|
||||
props.onClose();
|
||||
}}
|
||||
onViewPendingTx={() => {
|
||||
setScreen("tx-history");
|
||||
}}
|
||||
@@ -212,6 +221,86 @@ function ModalContent(props: ModalProps) {
|
||||
tx: props.tx,
|
||||
tokenSymbol: props.nativeTokenSymbol,
|
||||
}}
|
||||
theme={typeof props.theme === "string" ? props.theme : props.theme.type}
|
||||
payOptions={props.payOptions}
|
||||
onDone={() => {
|
||||
setScreen("execute-tx");
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ExecutingTxScreen(props: {
|
||||
tx: PreparedTransaction;
|
||||
closeModal: () => void;
|
||||
}) {
|
||||
const sendTxCore = useSendTransactionCore();
|
||||
const [status, setStatus] = useState<"loading" | "failed" | "sent">(
|
||||
"loading",
|
||||
);
|
||||
|
||||
const sendTx = useCallback(async () => {
|
||||
setStatus("loading");
|
||||
try {
|
||||
await sendTxCore.mutateAsync(props.tx);
|
||||
setStatus("sent");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setStatus("failed");
|
||||
}
|
||||
}, [sendTxCore, props.tx]);
|
||||
|
||||
const done = useRef(false);
|
||||
useEffect(() => {
|
||||
if (done.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
done.current = true;
|
||||
sendTx();
|
||||
}, [sendTx]);
|
||||
|
||||
return (
|
||||
<Container p="lg">
|
||||
<ModalHeader title="Transaction" />
|
||||
<Spacer y="xxl" />
|
||||
<Spacer y="xxl" />
|
||||
|
||||
<Container flex="row" center="x">
|
||||
{status === "loading" && <Spinner size="3xl" color="accentText" />}
|
||||
{status === "failed" && <AccentFailIcon size={iconSize["3xl"]} />}
|
||||
{status === "sent" && (
|
||||
<Container color="success" flex="row" center="both">
|
||||
<CheckCircledIcon
|
||||
width={iconSize["3xl"]}
|
||||
height={iconSize["3xl"]}
|
||||
/>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
<Spacer y="lg" />
|
||||
|
||||
<Text color="primaryText" center size="lg">
|
||||
{status === "loading" && "Sending transaction"}
|
||||
{status === "failed" && "Transaction failed"}
|
||||
{status === "sent" && "Transaction sent"}
|
||||
</Text>
|
||||
|
||||
<Spacer y="xxl" />
|
||||
<Spacer y="xxl" />
|
||||
|
||||
{status === "failed" && (
|
||||
<Button variant="accent" fullWidth onClick={sendTx}>
|
||||
Try Again
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{status === "sent" && (
|
||||
<Button variant="accent" fullWidth onClick={props.closeModal}>
|
||||
Done
|
||||
</Button>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ function ConnectButtonInner(
|
||||
|
||||
const supportedTokens = useMemo(() => {
|
||||
if (!props.supportedTokens) {
|
||||
return defaultTokens;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const tokens = { ...defaultTokens };
|
||||
|
||||
@@ -10,6 +10,72 @@ import type { NetworkSelectorProps } from "./NetworkSelector.js";
|
||||
import type { SupportedTokens } from "./defaultTokens.js";
|
||||
import type { WelcomeScreen } from "./screens/types.js";
|
||||
|
||||
export type PayUIOptions = {
|
||||
/**
|
||||
* Prefill the Buy Token amount, chain and/or token.
|
||||
* You can also disable the edits for the prefilled values using `allowEdits` - By default all are editable
|
||||
*
|
||||
* For example, if you want to allow changing the amount, but disable changing the token and chain,
|
||||
* you can set `allowEdits` to `{ amount: true, token: false, chain: false }`
|
||||
*
|
||||
* If no `token` object is not specified, native token will be prefilled by default
|
||||
*/
|
||||
prefillBuy?: {
|
||||
chain: Chain;
|
||||
token?: {
|
||||
name: string;
|
||||
symbol: string;
|
||||
address: string;
|
||||
icon?: string;
|
||||
};
|
||||
amount?: string;
|
||||
allowEdits?: {
|
||||
amount: boolean;
|
||||
token: boolean;
|
||||
chain: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure options for buying tokens using other token ( aka Swap )
|
||||
*
|
||||
* By default, the "Crypto" option is enabled. You can disable it by setting `buyWithCrypto` to `false`
|
||||
*
|
||||
* You can prefill the source token and chain using `prefillSource`
|
||||
* You can also disable the edits for the prefilled values by setting `prefillSource.allowEdits` - By default all are editable
|
||||
*
|
||||
* For example, if you want to allow selecting chain and but disable selecting token, you can set `allowEdits` to `{ token: false, chain: true }`
|
||||
*/
|
||||
buyWithCrypto?:
|
||||
| false
|
||||
| {
|
||||
prefillSource?: {
|
||||
chain: Chain;
|
||||
token?: {
|
||||
name: string;
|
||||
symbol: string;
|
||||
address: string;
|
||||
icon?: string;
|
||||
};
|
||||
allowEdits?: {
|
||||
token: boolean;
|
||||
chain: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* By default "Credit card" option is enabled. you can disable it by setting `buyWithFiat` to `false`
|
||||
*
|
||||
* You can also enable the test mode for the on-ramp provider to test on-ramp without using real credit card.
|
||||
*/
|
||||
buyWithFiat?:
|
||||
| {
|
||||
testMode?: boolean;
|
||||
}
|
||||
| false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for configuring the `ConnectButton`'s Connect Button
|
||||
* @connectWallet
|
||||
@@ -109,6 +175,13 @@ export type ConnectButton_detailsModalOptions = {
|
||||
* ```
|
||||
*/
|
||||
footer?: (props: { close: () => void }) => JSX.Element;
|
||||
|
||||
/**
|
||||
* Configure options for thirdweb Pay.
|
||||
*
|
||||
* thirdweb Pay allows users to buy tokens using crypto or fiat currency.
|
||||
*/
|
||||
payOptions?: PayUIOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
TextAlignJustifyIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useEffect, useState, useSyncExternalStore } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
|
||||
import type { Chain } from "../../../../chains/types.js";
|
||||
import { getContract } from "../../../../contract/contract.js";
|
||||
@@ -44,7 +44,7 @@ import { Button, IconButton } from "../components/buttons.js";
|
||||
import { Link, Text } from "../components/text.js";
|
||||
import { useCustomTheme } from "../design-system/CustomThemeProvider.js";
|
||||
import { fadeInAnimation } from "../design-system/animations.js";
|
||||
import { StyledButton, StyledDiv } from "../design-system/elements.js";
|
||||
import { StyledButton } from "../design-system/elements.js";
|
||||
import {
|
||||
type Theme,
|
||||
fontSize,
|
||||
@@ -64,11 +64,12 @@ import type { SupportedTokens } from "./defaultTokens.js";
|
||||
import { FundsIcon } from "./icons/FundsIcon.js";
|
||||
import { SmartWalletBadgeIcon } from "./icons/SmartAccountBadgeIcon.js";
|
||||
import { WalletIcon } from "./icons/WalletIcon.js";
|
||||
import { BuyScreen } from "./screens/Buy/SwapScreen.js";
|
||||
import { swapTransactionsStore } from "./screens/Buy/swap/pendingSwapTx.js";
|
||||
import { genericTokenIcon } from "./icons/dataUris.js";
|
||||
import { LazyBuyScreen } from "./screens/Buy/LazyBuyScreen.js";
|
||||
import { BuyTxHistory } from "./screens/Buy/tx-history/BuyTxHistory.js";
|
||||
import { ReceiveFunds } from "./screens/ReceiveFunds.js";
|
||||
import { SendFunds } from "./screens/SendFunds.js";
|
||||
import { SwapTransactionsScreen } from "./screens/SwapTransactionsScreen.js";
|
||||
import { ViewFunds } from "./screens/ViewFunds.js";
|
||||
|
||||
const TW_CONNECTED_WALLET = "tw-connected-wallet";
|
||||
|
||||
@@ -81,7 +82,8 @@ type WalletDetailsModalScreen =
|
||||
| "receive"
|
||||
| "buy"
|
||||
| "network-switcher"
|
||||
| "pending-tx";
|
||||
| "pending-tx"
|
||||
| "view-funds";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -91,23 +93,18 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
detailsButton?: ConnectButton_detailsButtonOptions;
|
||||
detailsModal?: ConnectButton_detailsModalOptions;
|
||||
theme: "light" | "dark" | Theme;
|
||||
supportedTokens: SupportedTokens;
|
||||
supportedTokens?: SupportedTokens;
|
||||
chains: Chain[];
|
||||
chain?: Chain;
|
||||
switchButton: ConnectButtonProps["switchButton"];
|
||||
}> = (props) => {
|
||||
const { connectLocale: locale, client } = useConnectUI();
|
||||
|
||||
const activeWallet = useActiveWallet();
|
||||
const activeAccount = useActiveAccount();
|
||||
const walletChain = useActiveWalletChain();
|
||||
const chainQuery = useChainQuery(walletChain);
|
||||
const { disconnect } = useDisconnect();
|
||||
const swapTxs = useSyncExternalStore(
|
||||
swapTransactionsStore.subscribe,
|
||||
swapTransactionsStore.getValue,
|
||||
);
|
||||
const pendingSwapTxs = swapTxs.filter((tx) => tx.status === "PENDING");
|
||||
|
||||
// prefetch chains metadata with low concurrency
|
||||
useChainsQuery(props.chains, 5);
|
||||
|
||||
@@ -480,12 +477,26 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
<TextAlignJustifyIcon width={iconSize.md} height={iconSize.md} />
|
||||
<Container flex="row" gap="xs" center="y">
|
||||
<Text color="primaryText">{locale.transactions}</Text>
|
||||
{pendingSwapTxs && pendingSwapTxs.length > 0 && (
|
||||
<BadgeCount>{pendingSwapTxs.length}</BadgeCount>
|
||||
)}
|
||||
</Container>
|
||||
</MenuButton>
|
||||
|
||||
<MenuButton
|
||||
onClick={() => {
|
||||
setScreen("view-funds");
|
||||
}}
|
||||
style={{
|
||||
fontSize: fontSize.sm,
|
||||
}}
|
||||
>
|
||||
<Img
|
||||
width={iconSize.md}
|
||||
height={iconSize.md}
|
||||
src={genericTokenIcon}
|
||||
client={client}
|
||||
/>
|
||||
<Text color="primaryText">View Funds</Text>
|
||||
</MenuButton>
|
||||
|
||||
{/* Switch to Personal Wallet */}
|
||||
{/* {personalWallet &&
|
||||
!props.detailsModal?.hideSwitchToPersonalWallet && (
|
||||
@@ -585,9 +596,14 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
|
||||
if (screen === "pending-tx") {
|
||||
content = (
|
||||
<SwapTransactionsScreen
|
||||
<BuyTxHistory
|
||||
isBuyForTx={false}
|
||||
isEmbed={false}
|
||||
onBack={() => setScreen("main")}
|
||||
client={client}
|
||||
onDone={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -629,6 +645,19 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
// );
|
||||
// }
|
||||
|
||||
// send funds
|
||||
else if (screen === "view-funds") {
|
||||
content = (
|
||||
<ViewFunds
|
||||
supportedTokens={props.supportedTokens}
|
||||
onBack={() => {
|
||||
setScreen("main");
|
||||
}}
|
||||
client={client}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// send funds
|
||||
else if (screen === "send") {
|
||||
content = (
|
||||
@@ -653,15 +682,21 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
);
|
||||
}
|
||||
|
||||
// swap tokens
|
||||
// thirdweb pay
|
||||
else if (screen === "buy") {
|
||||
content = (
|
||||
<BuyScreen
|
||||
<LazyBuyScreen
|
||||
isEmbed={false}
|
||||
client={client}
|
||||
onBack={() => setScreen("main")}
|
||||
supportedTokens={props.supportedTokens}
|
||||
onViewPendingTx={() => setScreen("pending-tx")}
|
||||
connectLocale={locale}
|
||||
payOptions={props.detailsModal?.payOptions || {}}
|
||||
theme={typeof props.theme === "string" ? props.theme : props.theme.type}
|
||||
onDone={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -751,22 +786,6 @@ const MenuButton = /* @__PURE__ */ StyledButton(() => {
|
||||
};
|
||||
});
|
||||
|
||||
const BadgeCount = /* @__PURE__ */ StyledDiv(() => {
|
||||
const theme = useCustomTheme();
|
||||
return {
|
||||
background: theme.colors.primaryButtonBg,
|
||||
color: theme.colors.primaryButtonText,
|
||||
fontSize: fontSize.sm,
|
||||
fontWeight: 500,
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minWidth: "22px",
|
||||
minHeight: "22px",
|
||||
};
|
||||
});
|
||||
|
||||
const MenuLink = /* @__PURE__ */ (() => MenuButton.withComponent("a"))();
|
||||
|
||||
const StyledChevronRightIcon = /* @__PURE__ */ styled(
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import type { Chain } from "../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../client/client.js";
|
||||
import type { SiweAuthOptions } from "../../../../../exports/react.js";
|
||||
import type { Wallet } from "../../../../../wallets/interfaces/wallet.js";
|
||||
import type { SmartWalletOptions } from "../../../../../wallets/smart/types.js";
|
||||
import type { AppMetadata } from "../../../../../wallets/types.js";
|
||||
import type { SiweAuthOptions } from "../../../../core/hooks/auth/useSiweAuth.js";
|
||||
import { useSiweAuth } from "../../../../core/hooks/auth/useSiweAuth.js";
|
||||
import { AutoConnect } from "../../../../core/hooks/connection/useAutoConnect.js";
|
||||
import {
|
||||
|
||||
@@ -2,7 +2,7 @@ export type TokenInfo = {
|
||||
name: string;
|
||||
symbol: string;
|
||||
address: string;
|
||||
icon: string;
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
const wrappedEthIcon =
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { IconFC } from "../types.js";
|
||||
|
||||
export const CADIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
viewBox="0 0 512 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<mask id="a">
|
||||
<circle cx="256" cy="256" r="256" fill="#fff" />
|
||||
</mask>
|
||||
<g mask="url(#a)">
|
||||
<path
|
||||
fill="#d80027"
|
||||
d="M0 0v512h144l112-64 112 64h144V0H368L256 64 144 0Z"
|
||||
/>
|
||||
<path fill="#eee" d="M144 0h224v512H144Z" />
|
||||
<path
|
||||
fill="#d80027"
|
||||
d="m301 289 44-22-22-11v-22l-45 22 23-44h-23l-22-34-22 33h-23l23 45-45-22v22l-22 11 45 22-12 23h45v33h22v-33h45z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { IconFC } from "../types.js";
|
||||
|
||||
export const EURIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
viewBox="0 0 512 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<mask id="a">
|
||||
<circle cx="256" cy="256" r="256" fill="#fff" />
|
||||
</mask>
|
||||
<g mask="url(#a)">
|
||||
<path fill="#0052b4" d="M0 0h512v512H0z" />
|
||||
<path
|
||||
fill="#ffda44"
|
||||
d="m256 100.2 8.3 25.5H291l-21.7 15.7 8.3 25.6-21.7-15.8-21.7 15.8 8.3-25.6-21.7-15.7h26.8zm-110.2 45.6 24 12.2 18.9-19-4.2 26.5 23.9 12.2-26.5 4.2-4.2 26.5-12.2-24-26.5 4.3 19-19zM100.2 256l25.5-8.3V221l15.7 21.7 25.6-8.3-15.8 21.7 15.8 21.7-25.6-8.3-15.7 21.7v-26.8zm45.6 110.2 12.2-24-19-18.9 26.5 4.2 12.2-23.9 4.2 26.5 26.5 4.2-24 12.2 4.3 26.5-19-19zM256 411.8l-8.3-25.5H221l21.7-15.7-8.3-25.6 21.7 15.8 21.7-15.8-8.3 25.6 21.7 15.7h-26.8zm110.2-45.6-24-12.2-18.9 19 4.2-26.5-23.9-12.2 26.5-4.2 4.2-26.5 12.2 24 26.5-4.3-19 19zM411.8 256l-25.5 8.3V291l-15.7-21.7-25.6 8.3 15.8-21.7-15.8-21.7 25.6 8.3 15.7-21.7v26.8zm-45.6-110.2-12.2 24 19 18.9-26.5-4.2-12.2 23.9-4.2-26.5-26.5-4.2 24-12.2-4.3-26.5 19 19z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
import type { IconFC } from "../types.js";
|
||||
|
||||
export const GBPIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
viewBox="0 0 512 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle fill="#F0F0F0" cx="256" cy="256" r="256" />
|
||||
<g>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M52.92,100.142c-20.109,26.163-35.272,56.318-44.101,89.077h133.178L52.92,100.142z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M503.181,189.219c-8.829-32.758-23.993-62.913-44.101-89.076l-89.075,89.076H503.181z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M8.819,322.784c8.83,32.758,23.993,62.913,44.101,89.075l89.074-89.075L8.819,322.784L8.819,322.784 z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M411.858,52.921c-26.163-20.109-56.317-35.272-89.076-44.102v133.177L411.858,52.921z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M100.142,459.079c26.163,20.109,56.318,35.272,89.076,44.102V370.005L100.142,459.079z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M189.217,8.819c-32.758,8.83-62.913,23.993-89.075,44.101l89.075,89.075V8.819z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M322.783,503.181c32.758-8.83,62.913-23.993,89.075-44.101l-89.075-89.075V503.181z"
|
||||
/>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M370.005,322.784l89.075,89.076c20.108-26.162,35.272-56.318,44.101-89.076H370.005z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M509.833,222.609h-220.44h-0.001V2.167C278.461,0.744,267.317,0,256,0 c-11.319,0-22.461,0.744-33.391,2.167v220.44v0.001H2.167C0.744,233.539,0,244.683,0,256c0,11.319,0.744,22.461,2.167,33.391 h220.44h0.001v220.442C233.539,511.256,244.681,512,256,512c11.317,0,22.461-0.743,33.391-2.167v-220.44v-0.001h220.442 C511.256,278.461,512,267.319,512,256C512,244.683,511.256,233.539,509.833,222.609z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M322.783,322.784L322.783,322.784L437.019,437.02c5.254-5.252,10.266-10.743,15.048-16.435 l-97.802-97.802h-31.482V322.784z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M189.217,322.784h-0.002L74.98,437.019c5.252,5.254,10.743,10.266,16.435,15.048l97.802-97.804 V322.784z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M189.217,189.219v-0.002L74.981,74.98c-5.254,5.252-10.266,10.743-15.048,16.435l97.803,97.803 H189.217z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M322.783,189.219L322.783,189.219L437.02,74.981c-5.252-5.254-10.743-10.266-16.435-15.047 l-97.802,97.803V189.219z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { IconFC } from "../types.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const USDIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 512 512"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle fill="#F0F0F0" cx="256" cy="256" r="256" />
|
||||
<g>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M244.87,256H512c0-23.106-3.08-45.49-8.819-66.783H244.87V256z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M244.87,122.435h229.556c-15.671-25.572-35.708-48.175-59.07-66.783H244.87V122.435z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M256,512c60.249,0,115.626-20.824,159.356-55.652H96.644C140.374,491.176,195.751,512,256,512z"
|
||||
/>
|
||||
<path
|
||||
fill="#D80027"
|
||||
d="M37.574,389.565h436.852c12.581-20.529,22.338-42.969,28.755-66.783H8.819 C15.236,346.596,24.993,369.036,37.574,389.565z"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
fill="#0052B4"
|
||||
d="M118.584,39.978h23.329l-21.7,15.765l8.289,25.509l-21.699-15.765L85.104,81.252l7.16-22.037 C73.158,75.13,56.412,93.776,42.612,114.552h7.475l-13.813,10.035c-2.152,3.59-4.216,7.237-6.194,10.938l6.596,20.301l-12.306-8.941 c-3.059,6.481-5.857,13.108-8.372,19.873l7.267,22.368h26.822l-21.7,15.765l8.289,25.509l-21.699-15.765l-12.998,9.444 C0.678,234.537,0,245.189,0,256h256c0-141.384,0-158.052,0-256C205.428,0,158.285,14.67,118.584,39.978z M128.502,230.4 l-21.699-15.765L85.104,230.4l8.289-25.509l-21.7-15.765h26.822l8.288-25.509l8.288,25.509h26.822l-21.7,15.765L128.502,230.4z M120.213,130.317l8.289,25.509l-21.699-15.765l-21.699,15.765l8.289-25.509l-21.7-15.765h26.822l8.288-25.509l8.288,25.509h26.822 L120.213,130.317z M220.328,230.4l-21.699-15.765L176.93,230.4l8.289-25.509l-21.7-15.765h26.822l8.288-25.509l8.288,25.509h26.822 l-21.7,15.765L220.328,230.4z M212.039,130.317l8.289,25.509l-21.699-15.765l-21.699,15.765l8.289-25.509l-21.7-15.765h26.822 l8.288-25.509l8.288,25.509h26.822L212.039,130.317z M212.039,55.743l8.289,25.509l-21.699-15.765L176.93,81.252l8.289-25.509 l-21.7-15.765h26.822l8.288-25.509l8.288,25.509h26.822L212.039,55.743z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
import styled from "@emotion/styled";
|
||||
import { useMemo, useState } from "react";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { isAddress } from "../../../../../../utils/address.js";
|
||||
import type {
|
||||
Account,
|
||||
Wallet,
|
||||
} from "../../../../../../wallets/interfaces/wallet.js";
|
||||
import { Spacer } from "../../../components/Spacer.js";
|
||||
import { Container } from "../../../components/basic.js";
|
||||
import { Button } from "../../../components/buttons.js";
|
||||
import { Input } from "../../../components/formElements.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import { useCustomTheme } from "../../../design-system/CustomThemeProvider.js";
|
||||
import { AccountSelectorButton } from "./AccountSelectorButton.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function AccountSelectionScreen(props: {
|
||||
activeWallet: Wallet;
|
||||
activeAccount: Account;
|
||||
onSelect: (address: string) => void;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const [address, setAddress] = useState<string>("");
|
||||
const isValidAddress = useMemo(() => isAddress(address), [address]);
|
||||
const showError = !!address && !isValidAddress;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Text size="lg" color="primaryText">
|
||||
Send to
|
||||
</Text>
|
||||
<Spacer y="lg" />
|
||||
<Container
|
||||
flex="row"
|
||||
center="y"
|
||||
style={{
|
||||
flexWrap: "nowrap",
|
||||
height: "50px",
|
||||
}}
|
||||
>
|
||||
<StyledInput
|
||||
data-is-error={showError}
|
||||
value={address}
|
||||
placeholder="Enter wallet address"
|
||||
variant="outline"
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
variant="accent"
|
||||
disabled={!isValidAddress}
|
||||
style={{
|
||||
height: "100%",
|
||||
minWidth: "100px",
|
||||
borderTopLeftRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
}}
|
||||
onClick={() => {
|
||||
props.onSelect(address);
|
||||
}}
|
||||
>
|
||||
Confirm
|
||||
</Button>
|
||||
</Container>
|
||||
|
||||
{showError && (
|
||||
<>
|
||||
<Spacer y="xxs" />
|
||||
<Text color="danger" size="sm">
|
||||
Invalid address
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Spacer y="xl" />
|
||||
<Text size="sm">Connected</Text>
|
||||
<Spacer y="xs" />
|
||||
<AccountSelectorButton
|
||||
client={props.client}
|
||||
address={props.activeAccount.address}
|
||||
activeAccount={props.activeAccount}
|
||||
activeWallet={props.activeWallet}
|
||||
onClick={() => {
|
||||
props.onSelect(props.activeAccount.address);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledInput = /* @__PURE__ */ styled(Input)(() => {
|
||||
const theme = useCustomTheme();
|
||||
return {
|
||||
border: `1.5px solid ${theme.colors.borderColor}`,
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
height: "100%",
|
||||
boxSizing: "border-box",
|
||||
boxShadow: "none",
|
||||
borderRight: "none",
|
||||
"&:focus": {
|
||||
boxShadow: "none",
|
||||
borderColor: theme.colors.accentText,
|
||||
},
|
||||
"&[data-is-error='true']": {
|
||||
boxShadow: "none",
|
||||
borderColor: theme.colors.danger,
|
||||
},
|
||||
};
|
||||
});
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
import { ChevronDownIcon } from "@radix-ui/react-icons";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import type {
|
||||
Account,
|
||||
Wallet,
|
||||
} from "../../../../../../wallets/interfaces/wallet.js";
|
||||
import { shortenString } from "../../../../../core/utils/addresses.js";
|
||||
import { WalletImage } from "../../../components/WalletImage.js";
|
||||
import { Container } from "../../../components/basic.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import { iconSize } from "../../../design-system/index.js";
|
||||
import { WalletIcon } from "../../icons/WalletIcon.js";
|
||||
import { SecondaryButton } from "./buttons.js";
|
||||
|
||||
/**
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function AccountSelectorButton(props: {
|
||||
onClick: () => void;
|
||||
activeWallet: Wallet;
|
||||
activeAccount: Account;
|
||||
address: string;
|
||||
chevron?: boolean;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
return (
|
||||
<SecondaryButton variant="secondary" fullWidth onClick={props.onClick}>
|
||||
{props.activeAccount.address === props.address ? (
|
||||
<WalletImage
|
||||
id={props.activeWallet.id}
|
||||
size={iconSize.md}
|
||||
client={props.client}
|
||||
/>
|
||||
) : (
|
||||
<Container color="secondaryText" flex="row" center="both">
|
||||
<WalletIcon size={iconSize.md} />
|
||||
</Container>
|
||||
)}
|
||||
|
||||
<Text size="sm" color="primaryText">
|
||||
{shortenString(props.address, false)}
|
||||
</Text>
|
||||
{props.chevron && (
|
||||
<ChevronDownIcon
|
||||
width={iconSize.sm}
|
||||
height={iconSize.sm}
|
||||
style={{
|
||||
marginLeft: "auto",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</SecondaryButton>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
import { ClockIcon } from "@radix-ui/react-icons";
|
||||
import { Skeleton } from "../../../components/Skeleton.js";
|
||||
import { Container } from "../../../components/basic.js";
|
||||
import { Button } from "../../../components/buttons.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import { fontSize, iconSize, radius } from "../../../design-system/index.js";
|
||||
import type { IconFC } from "../../icons/types.js";
|
||||
import { formatSeconds } from "./swap/formatSeconds.js";
|
||||
|
||||
export function EstimatedTimeAndFees(props: {
|
||||
estimatedSeconds?: number | undefined;
|
||||
quoteIsLoading: boolean;
|
||||
onViewFees: () => void;
|
||||
}) {
|
||||
const { estimatedSeconds, quoteIsLoading } = props;
|
||||
|
||||
return (
|
||||
<Container
|
||||
bg="tertiaryBg"
|
||||
flex="row"
|
||||
borderColor="borderColor"
|
||||
style={{
|
||||
borderRadius: radius.md,
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
borderWidth: "1px",
|
||||
borderStyle: "solid",
|
||||
}}
|
||||
>
|
||||
<Container flex="row" center="y" gap="xxs" color="accentText" p="sm">
|
||||
<ClockIcon width={iconSize.sm} height={iconSize.sm} />
|
||||
{quoteIsLoading ? (
|
||||
<Skeleton height={fontSize.xs} width="50px" color="borderColor" />
|
||||
) : (
|
||||
<Text size="xs" color="secondaryText">
|
||||
{estimatedSeconds !== undefined
|
||||
? `~${formatSeconds(estimatedSeconds)}`
|
||||
: "--"}
|
||||
</Text>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
<Button variant="ghost" onClick={props.onViewFees} gap="xs">
|
||||
<Container color="accentText" flex="row" center="both">
|
||||
<ViewFeeIcon size={iconSize.sm} />
|
||||
</Container>
|
||||
<Text size="xs" color="secondaryText">
|
||||
View Fees
|
||||
</Text>
|
||||
</Button>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const ViewFeeIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M9.5 1.5H2.5C1.94772 1.5 1.5 1.94772 1.5 2.5V9.5C1.5 10.0523 1.94772 10.5 2.5 10.5H9.5C10.0523 10.5 10.5 10.0523 10.5 9.5V2.5C10.5 1.94772 10.0523 1.5 9.5 1.5Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.5 7.5L7.5 4.5"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Suspense, lazy } from "react";
|
||||
import { LoadingScreen } from "../../../../wallets/shared/LoadingScreen.js";
|
||||
import type { BuyScreenProps } from "./BuyScreen.js";
|
||||
|
||||
const BuyScreen = lazy(() => import("./BuyScreen.js"));
|
||||
|
||||
export function LazyBuyScreen(props: BuyScreenProps) {
|
||||
return (
|
||||
<Suspense fallback={<LoadingScreen />}>
|
||||
<BuyScreen {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import styled from "@emotion/styled";
|
||||
import { ChevronDownIcon } from "@radix-ui/react-icons";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { formatNumber } from "../../../../../../utils/formatNumber.js";
|
||||
import { Skeleton } from "../../../components/Skeleton.js";
|
||||
import { Container } from "../../../components/basic.js";
|
||||
import { Button } from "../../../components/buttons.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import {
|
||||
fontSize,
|
||||
iconSize,
|
||||
radius,
|
||||
spacing,
|
||||
} from "../../../design-system/index.js";
|
||||
import type { CurrencyMeta } from "./fiat/currencies.js";
|
||||
|
||||
/**
|
||||
* Shows an amount "value" and renders the selected token and chain
|
||||
* It also renders the buttons to select the token and chain
|
||||
* It also renders the balance of active wallet for the selected token in selected chain
|
||||
* @internal
|
||||
*/
|
||||
export function PayWithCreditCard(props: {
|
||||
value?: string;
|
||||
isLoading: boolean;
|
||||
client: ThirdwebClient;
|
||||
currency: CurrencyMeta;
|
||||
onSelectCurrency: () => void;
|
||||
disableCurrencySelection?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Container
|
||||
bg="tertiaryBg"
|
||||
borderColor="borderColor"
|
||||
flex="row"
|
||||
style={{
|
||||
borderRadius: radius.md,
|
||||
borderBottomRightRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderWidth: "1px",
|
||||
borderStyle: "solid",
|
||||
borderBottom: "none",
|
||||
flexWrap: "nowrap",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{/* Left */}
|
||||
<CurrencyButton
|
||||
disabled={props.disableCurrencySelection}
|
||||
variant="ghost"
|
||||
onClick={props.onSelectCurrency}
|
||||
style={{
|
||||
minHeight: "64px",
|
||||
justifyContent: "flex-start",
|
||||
minWidth: "50%",
|
||||
}}
|
||||
gap="sm"
|
||||
>
|
||||
<props.currency.icon size={iconSize.md} />
|
||||
<Container flex="row" center="y" gap="xxs">
|
||||
<Text color="primaryText">{props.currency.shorthand}</Text>
|
||||
{!props.disableCurrencySelection && (
|
||||
<ChevronDownIcon width={iconSize.sm} height={iconSize.sm} />
|
||||
)}
|
||||
</Container>
|
||||
</CurrencyButton>
|
||||
|
||||
{/* Right */}
|
||||
<div
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-end",
|
||||
gap: spacing.xxs,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
justifyContent: "center",
|
||||
paddingRight: spacing.sm,
|
||||
}}
|
||||
>
|
||||
{props.isLoading ? (
|
||||
<Skeleton width="100px" height={fontSize.lg} />
|
||||
) : (
|
||||
<Text size="lg" color={props.value ? "primaryText" : "secondaryText"}>
|
||||
{props.value ? `${formatNumber(Number(props.value), 4)}` : "--"}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const CurrencyButton = /* @__PURE__ */ styled(Button)(() => {
|
||||
return {
|
||||
"&[disabled]:hover": {
|
||||
borderColor: "transparent",
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -4,13 +4,15 @@ import { Container } from "../../../components/basic.js";
|
||||
import { Button } from "../../../components/buttons.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import { useCustomTheme } from "../../../design-system/CustomThemeProvider.js";
|
||||
import { StyledDiv } from "../../../design-system/elements.js";
|
||||
import { fontSize, radius, spacing } from "../../../design-system/index.js";
|
||||
import { fontSize, spacing } from "../../../design-system/index.js";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function PaymentSelection() {
|
||||
export function PaymentSelection(props: {
|
||||
selected: "crypto" | "creditCard";
|
||||
onSelect: (method: "crypto" | "creditCard") => void;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<Text size="sm">Pay with </Text>
|
||||
@@ -22,28 +24,25 @@ export function PaymentSelection() {
|
||||
gridGap: spacing.sm,
|
||||
}}
|
||||
>
|
||||
<CheckButton isChecked={true} variant="outline">
|
||||
<Container gap="xxs" flex="row" center="y">
|
||||
Crypto
|
||||
</Container>
|
||||
</CheckButton>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
<CheckButton
|
||||
isChecked={props.selected === "creditCard"}
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
props.onSelect("creditCard");
|
||||
}}
|
||||
>
|
||||
<CheckButton
|
||||
variant="outline"
|
||||
isChecked={false}
|
||||
style={{
|
||||
opacity: 0.5,
|
||||
}}
|
||||
disabled
|
||||
>
|
||||
Credit Card
|
||||
</CheckButton>
|
||||
<FloatingBadge> Coming Soon </FloatingBadge>
|
||||
</div>
|
||||
Credit Card
|
||||
</CheckButton>
|
||||
|
||||
<CheckButton
|
||||
isChecked={props.selected === "crypto"}
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
props.onSelect("crypto");
|
||||
}}
|
||||
>
|
||||
Crypto
|
||||
</CheckButton>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
@@ -59,6 +58,11 @@ const CheckButton = /* @__PURE__ */ styled(Button)(
|
||||
borderColor: props.isChecked
|
||||
? theme.colors.accentText
|
||||
: theme.colors.borderColor,
|
||||
"&:hover": {
|
||||
borderColor: props.isChecked
|
||||
? theme.colors.accentText
|
||||
: theme.colors.secondaryText,
|
||||
},
|
||||
gap: spacing.xs,
|
||||
paddingInline: spacing.xxs,
|
||||
paddingBlock: spacing.sm,
|
||||
@@ -66,19 +70,3 @@ const CheckButton = /* @__PURE__ */ styled(Button)(
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const FloatingBadge = /* @__PURE__ */ StyledDiv(() => {
|
||||
const theme = useCustomTheme();
|
||||
return {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
transform: "translate(10%, -60%)",
|
||||
backgroundColor: theme.colors.secondaryButtonBg,
|
||||
paddingBlock: "3px",
|
||||
paddingInline: spacing.xs,
|
||||
fontSize: fontSize.xs,
|
||||
borderRadius: radius.sm,
|
||||
color: theme.colors.accentText,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { keyframes } from "@emotion/react";
|
||||
import { CheckIcon } from "@radix-ui/react-icons";
|
||||
import { Container } from "../../../components/basic.js";
|
||||
import { StyledDiv } from "../../../design-system/elements.js";
|
||||
import { fontSize, iconSize } from "../../../design-system/index.js";
|
||||
|
||||
export function StepIcon(props: {
|
||||
isDone: boolean;
|
||||
isActive: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Container
|
||||
flex="row"
|
||||
center="both"
|
||||
color={
|
||||
props.isDone
|
||||
? "success"
|
||||
: props.isActive
|
||||
? "accentText"
|
||||
: "secondaryText"
|
||||
}
|
||||
>
|
||||
<Circle>
|
||||
{props.isDone ? (
|
||||
<CheckIcon width={iconSize.sm} height={iconSize.sm} />
|
||||
) : (
|
||||
<PulsingDot data-active={props.isActive} />
|
||||
)}
|
||||
</Circle>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export function Step(props: {
|
||||
isDone: boolean;
|
||||
label: string;
|
||||
isActive: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Container
|
||||
flex="row"
|
||||
center="y"
|
||||
gap="xs"
|
||||
style={{
|
||||
fontSize: fontSize.sm,
|
||||
}}
|
||||
color={
|
||||
props.isDone
|
||||
? "success"
|
||||
: props.isActive
|
||||
? "accentText"
|
||||
: "secondaryText"
|
||||
}
|
||||
>
|
||||
<StepIcon isDone={props.isDone} isActive={props.isActive} />
|
||||
{props.label}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const pulseAnimation = keyframes`
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
`;
|
||||
|
||||
const PulsingDot = /* @__PURE__ */ StyledDiv(() => {
|
||||
return {
|
||||
background: "currentColor",
|
||||
width: "9px",
|
||||
height: "9px",
|
||||
borderRadius: "50%",
|
||||
'&[data-active="true"]': {
|
||||
animation: `${pulseAnimation} 1s infinite`,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const Circle = /* @__PURE__ */ StyledDiv(() => {
|
||||
return {
|
||||
border: "1px solid currentColor",
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
};
|
||||
});
|
||||
@@ -1,800 +0,0 @@
|
||||
import { ClockIcon, CrossCircledIcon } from "@radix-ui/react-icons";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { polygon } from "../../../../../../chains/chain-definitions/polygon.js";
|
||||
import type { Chain } from "../../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../constants/addresses.js";
|
||||
import type { BuyWithCryptoQuote } from "../../../../../../pay/buyWithCrypto/actions/getQuote.js";
|
||||
import type { PreparedTransaction } from "../../../../../../transaction/prepare-transaction.js";
|
||||
import { formatNumber } from "../../../../../../utils/formatNumber.js";
|
||||
import { toEther } from "../../../../../../utils/units.js";
|
||||
import type {
|
||||
Account,
|
||||
Wallet,
|
||||
} from "../../../../../../wallets/interfaces/wallet.js";
|
||||
import { getTotalTxCostForBuy } from "../../../../../core/hooks/contract/useSendTransaction.js";
|
||||
import {
|
||||
useChainQuery,
|
||||
useChainsQuery,
|
||||
} from "../../../../../core/hooks/others/useChainQuery.js";
|
||||
import { useWalletBalance } from "../../../../../core/hooks/others/useWalletBalance.js";
|
||||
import {
|
||||
type BuyWithCryptoQuoteQueryParams,
|
||||
useBuyWithCryptoQuote,
|
||||
} from "../../../../../core/hooks/pay/useBuyWithCryptoQuote.js";
|
||||
import {
|
||||
useActiveAccount,
|
||||
useActiveWallet,
|
||||
useActiveWalletChain,
|
||||
useSwitchActiveWalletChain,
|
||||
} from "../../../../../core/hooks/wallets/wallet-hooks.js";
|
||||
import { wait } from "../../../../../core/utils/wait.js";
|
||||
import { LoadingScreen } from "../../../../wallets/shared/LoadingScreen.js";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerOverlay,
|
||||
useDrawer,
|
||||
} from "../../../components/Drawer.js";
|
||||
import { DynamicHeight } from "../../../components/DynamicHeight.js";
|
||||
import { Skeleton } from "../../../components/Skeleton.js";
|
||||
import { Spacer } from "../../../components/Spacer.js";
|
||||
import { Spinner } from "../../../components/Spinner.js";
|
||||
import { TokenIcon } from "../../../components/TokenIcon.js";
|
||||
import { Container, Line, ModalHeader } from "../../../components/basic.js";
|
||||
import { Button } from "../../../components/buttons.js";
|
||||
import { Text } from "../../../components/text.js";
|
||||
import { fontSize, iconSize, radius } from "../../../design-system/index.js";
|
||||
import { useDebouncedValue } from "../../../hooks/useDebouncedValue.js";
|
||||
import type { SupportedTokens } from "../../defaultTokens.js";
|
||||
import type { IconFC } from "../../icons/types.js";
|
||||
import type { ConnectLocale } from "../../locale/types.js";
|
||||
import { TokenSelector } from "../TokenSelector.js";
|
||||
import {
|
||||
type ERC20OrNativeToken,
|
||||
NATIVE_TOKEN,
|
||||
isNativeToken,
|
||||
} from "../nativeToken.js";
|
||||
import { AccountSelectionScreen } from "./AccountSelectionScreen.js";
|
||||
import { AccountSelectorButton } from "./AccountSelectorButton.js";
|
||||
import { PaymentSelection } from "./PaymentSelection.js";
|
||||
import { FeesButton } from "./buttons.js";
|
||||
import { BuyTokenInput } from "./swap/BuyTokenInput.js";
|
||||
import { SwapConfirmationScreen } from "./swap/ConfirmationScreen.js";
|
||||
import { SwapFees } from "./swap/Fees.js";
|
||||
import { PayWithCrypto } from "./swap/PayWithCrypto.js";
|
||||
import { formatSeconds } from "./swap/formatSeconds.js";
|
||||
import { useSwapSupportedChains } from "./swap/useSwapSupportedChains.js";
|
||||
|
||||
// NOTE: Must not use useConnectUI here because this UI can be used outside connect ui
|
||||
|
||||
type BuyForTx = {
|
||||
cost: bigint;
|
||||
balance: bigint;
|
||||
tx: PreparedTransaction;
|
||||
tokenSymbol: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function BuyScreen(props: {
|
||||
onBack: () => void;
|
||||
supportedTokens: SupportedTokens;
|
||||
onViewPendingTx: () => void;
|
||||
client: ThirdwebClient;
|
||||
connectLocale: ConnectLocale;
|
||||
buyForTx?: BuyForTx;
|
||||
}) {
|
||||
const activeChain = useActiveWalletChain();
|
||||
const activeWallet = useActiveWallet();
|
||||
const account = useActiveAccount();
|
||||
const supportedChainsQuery = useSwapSupportedChains(props.client);
|
||||
|
||||
if (!activeChain || !account || !activeWallet || !supportedChainsQuery.data) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
||||
return (
|
||||
<BuyScreenContent
|
||||
{...props}
|
||||
activeChain={activeChain}
|
||||
activeWallet={activeWallet}
|
||||
account={account}
|
||||
onViewPendingTx={props.onViewPendingTx}
|
||||
supportedChains={supportedChainsQuery.data}
|
||||
buyForTx={props.buyForTx}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
type Screen =
|
||||
| "main"
|
||||
| "select-from-token"
|
||||
| "select-to-token"
|
||||
| "confirmation"
|
||||
| "usd-confirmation"
|
||||
| "kado-iframe";
|
||||
type DrawerScreen = "fees" | "address" | undefined;
|
||||
|
||||
/**
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function BuyScreenContent(props: {
|
||||
client: ThirdwebClient;
|
||||
onBack: () => void;
|
||||
supportedTokens: SupportedTokens;
|
||||
activeChain: Chain;
|
||||
activeWallet: Wallet;
|
||||
account: Account;
|
||||
onViewPendingTx: () => void;
|
||||
supportedChains: Chain[];
|
||||
connectLocale: ConnectLocale;
|
||||
buyForTx?: BuyForTx;
|
||||
}) {
|
||||
const {
|
||||
activeChain,
|
||||
account,
|
||||
client,
|
||||
activeWallet,
|
||||
supportedChains,
|
||||
connectLocale,
|
||||
} = props;
|
||||
const [isSwitching, setIsSwitching] = useState(false);
|
||||
const switchActiveWalletChain = useSwitchActiveWalletChain();
|
||||
const [method] = useState<"crypto" | "creditCard">("crypto");
|
||||
|
||||
// prefetch chains metadata
|
||||
useChainsQuery(supportedChains || [], 50);
|
||||
|
||||
// screens
|
||||
const [screen, setScreen] = useState<Screen>("main");
|
||||
const [drawerScreen, setDrawerScreen] = useState<DrawerScreen>();
|
||||
const { drawerRef, drawerOverlayRef, onClose } = useDrawer();
|
||||
|
||||
const closeDrawer = () => {
|
||||
onClose(() => {
|
||||
setDrawerScreen(undefined);
|
||||
});
|
||||
};
|
||||
|
||||
const initialTokenAmount = props.buyForTx
|
||||
? formatNumber(
|
||||
Number(toEther(props.buyForTx.cost - props.buyForTx.balance)),
|
||||
4,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
// token amount
|
||||
const [tokenAmount, setTokenAmount] = useState<string>(
|
||||
initialTokenAmount ? String(initialTokenAmount) : "",
|
||||
);
|
||||
|
||||
// once the user edits the tokenInput or confirms the Buy - stop updating the token amount
|
||||
const [stopUpdatingTokenAmount, setStopUpdatingTokenAmount] = useState(
|
||||
!props.buyForTx,
|
||||
);
|
||||
|
||||
const [amountNeeded, setAmountNeeded] = useState<bigint | undefined>(
|
||||
props.buyForTx?.cost,
|
||||
);
|
||||
|
||||
// update amount needed every 30 seconds
|
||||
// also update the token amount if allowed
|
||||
// ( Can't use useQuery because tx can't be added to queryKey )
|
||||
useEffect(() => {
|
||||
const buyTx = props.buyForTx;
|
||||
if (!buyTx || stopUpdatingTokenAmount) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mounted = true;
|
||||
|
||||
async function pollTxCost() {
|
||||
if (!buyTx || !mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const totalCost = await getTotalTxCostForBuy(buyTx.tx);
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
setAmountNeeded(totalCost);
|
||||
|
||||
if (totalCost > buyTx.balance) {
|
||||
const _tokenAmount = String(
|
||||
formatNumber(Number(toEther(totalCost - buyTx.balance)), 4),
|
||||
);
|
||||
setTokenAmount(_tokenAmount);
|
||||
}
|
||||
} catch {
|
||||
// no op
|
||||
}
|
||||
|
||||
await wait(30000);
|
||||
pollTxCost();
|
||||
}
|
||||
|
||||
pollTxCost();
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [props.buyForTx, stopUpdatingTokenAmount]);
|
||||
|
||||
const [hasEditedAmount, setHasEditedAmount] = useState(false);
|
||||
const isMiniScreen = props.buyForTx ? false : !hasEditedAmount;
|
||||
|
||||
const isChainSupported = useMemo(
|
||||
() => supportedChains?.find((c) => c.id === activeChain.id),
|
||||
[activeChain.id, supportedChains],
|
||||
);
|
||||
|
||||
// selected chain
|
||||
const defaultChain = isChainSupported ? activeChain : polygon;
|
||||
const [fromChain, setFromChain] = useState<Chain>(
|
||||
props.buyForTx ? props.buyForTx.tx.chain : defaultChain,
|
||||
);
|
||||
|
||||
const [toChain, setToChain] = useState<Chain>(
|
||||
props.buyForTx ? props.buyForTx.tx.chain : defaultChain,
|
||||
);
|
||||
const [address, setAddress] = useState<string>(account.address);
|
||||
|
||||
// selected tokens
|
||||
const [fromToken, setFromToken] = useState<ERC20OrNativeToken>(
|
||||
(props.buyForTx ? props.supportedTokens[toChain.id]?.[0] : undefined) ||
|
||||
NATIVE_TOKEN,
|
||||
);
|
||||
|
||||
const [toToken, setToToken] = useState<ERC20OrNativeToken>(
|
||||
props.buyForTx
|
||||
? NATIVE_TOKEN
|
||||
: props.supportedTokens[toChain.id]?.[0] || NATIVE_TOKEN,
|
||||
);
|
||||
|
||||
const deferredTokenAmount = useDebouncedValue(tokenAmount, 300);
|
||||
|
||||
const fromTokenBalanceQuery = useWalletBalance({
|
||||
address: account.address,
|
||||
chain: fromChain,
|
||||
tokenAddress: isNativeToken(fromToken) ? undefined : fromToken.address,
|
||||
client,
|
||||
});
|
||||
|
||||
// when a quote is finalized ( approve sent if required or swap sent )
|
||||
// we save it here to stop refetching the quote query
|
||||
const [finalizedQuote, setFinalizedQuote] = useState<
|
||||
BuyWithCryptoQuote | undefined
|
||||
>();
|
||||
|
||||
const buyWithCryptoParams: BuyWithCryptoQuoteQueryParams | undefined =
|
||||
deferredTokenAmount &&
|
||||
!finalizedQuote &&
|
||||
!(fromChain.id === toChain.id && fromToken === toToken)
|
||||
? {
|
||||
// wallet
|
||||
fromAddress: address,
|
||||
// from token
|
||||
fromChainId: fromChain.id,
|
||||
fromTokenAddress: isNativeToken(fromToken)
|
||||
? NATIVE_TOKEN_ADDRESS
|
||||
: fromToken.address,
|
||||
toChainId: toChain.id,
|
||||
// to
|
||||
toTokenAddress: isNativeToken(toToken)
|
||||
? NATIVE_TOKEN_ADDRESS
|
||||
: toToken.address,
|
||||
toAmount: deferredTokenAmount,
|
||||
client,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(buyWithCryptoParams, {
|
||||
// refetch every 30 seconds
|
||||
staleTime: 30 * 1000,
|
||||
refetchInterval: 30 * 1000,
|
||||
gcTime: 30 * 1000,
|
||||
});
|
||||
|
||||
if (screen === "select-from-token") {
|
||||
return (
|
||||
<TokenSelector
|
||||
onBack={() => setScreen("main")}
|
||||
tokenList={
|
||||
(fromChain?.id ? props.supportedTokens[fromChain.id] : undefined) ||
|
||||
[]
|
||||
}
|
||||
onTokenSelect={(tokenInfo) => {
|
||||
setFromToken(tokenInfo);
|
||||
setScreen("main");
|
||||
}}
|
||||
chain={fromChain}
|
||||
chainSelection={{
|
||||
chains: supportedChains,
|
||||
select: (c) => setFromChain(c),
|
||||
}}
|
||||
connectLocale={connectLocale}
|
||||
client={client}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (screen === "select-to-token") {
|
||||
return (
|
||||
<TokenSelector
|
||||
onBack={() => setScreen("main")}
|
||||
tokenList={
|
||||
(toChain?.id ? props.supportedTokens[toChain.id] : undefined) || []
|
||||
}
|
||||
onTokenSelect={(tokenInfo) => {
|
||||
setToToken(tokenInfo);
|
||||
setScreen("main");
|
||||
}}
|
||||
chain={toChain}
|
||||
chainSelection={{
|
||||
chains: supportedChains,
|
||||
select: (c) => setToChain(c),
|
||||
}}
|
||||
connectLocale={connectLocale}
|
||||
client={client}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const swapQuote = buyWithCryptoQuoteQuery.data;
|
||||
const isSwapQuoteError = buyWithCryptoQuoteQuery.isError;
|
||||
|
||||
const getErrorMessage = () => {
|
||||
const defaultMessage = "Unable to get price quote";
|
||||
try {
|
||||
if (buyWithCryptoQuoteQuery.error instanceof Error) {
|
||||
if (buyWithCryptoQuoteQuery.error.message.includes("Minimum")) {
|
||||
const msg = buyWithCryptoQuoteQuery.error.message;
|
||||
return msg.replace("Fetch failed: Error: ", "");
|
||||
}
|
||||
}
|
||||
return defaultMessage;
|
||||
} catch {
|
||||
return defaultMessage;
|
||||
}
|
||||
};
|
||||
|
||||
const sourceTokenAmount = swapQuote?.swapDetails.fromAmount || "";
|
||||
const quoteToConfirm = finalizedQuote || buyWithCryptoQuoteQuery.data;
|
||||
|
||||
if (screen === "confirmation" && quoteToConfirm) {
|
||||
return (
|
||||
<SwapConfirmationScreen
|
||||
client={client}
|
||||
onBack={() => {
|
||||
// remove finalized quote when going back
|
||||
setFinalizedQuote(undefined);
|
||||
setStopUpdatingTokenAmount(true);
|
||||
setScreen("main");
|
||||
}}
|
||||
buyWithCryptoQuote={quoteToConfirm}
|
||||
onQuoteFinalized={(_quote) => {
|
||||
setFinalizedQuote(_quote);
|
||||
}}
|
||||
fromAmount={quoteToConfirm.swapDetails.fromAmount}
|
||||
toAmount={tokenAmount}
|
||||
fromChain={fromChain}
|
||||
toChain={toChain}
|
||||
account={account}
|
||||
fromToken={fromToken}
|
||||
toToken={toToken}
|
||||
onViewPendingTx={props.onViewPendingTx}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isNotEnoughBalance =
|
||||
!!sourceTokenAmount &&
|
||||
!!fromTokenBalanceQuery.data &&
|
||||
Number(fromTokenBalanceQuery.data.displayValue) < Number(sourceTokenAmount);
|
||||
|
||||
const disableContinue = !swapQuote || isNotEnoughBalance;
|
||||
const switchChainRequired = props.activeChain.id !== fromChain.id;
|
||||
|
||||
return (
|
||||
<Container animate="fadein">
|
||||
{/* biome-ignore lint/a11y/useKeyWithClickEvents: <explanation> */}
|
||||
<div
|
||||
onClick={(e) => {
|
||||
if (
|
||||
drawerScreen &&
|
||||
drawerRef.current &&
|
||||
!drawerRef.current.contains(e.target as Node)
|
||||
) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
closeDrawer();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{/* Drawer */}
|
||||
{drawerScreen && (
|
||||
<>
|
||||
<DrawerOverlay ref={drawerOverlayRef} />
|
||||
<Drawer ref={drawerRef} close={closeDrawer}>
|
||||
<DynamicHeight>
|
||||
{drawerScreen === "address" && (
|
||||
<AccountSelectionScreen
|
||||
onSelect={(v) => {
|
||||
setAddress(v);
|
||||
closeDrawer();
|
||||
}}
|
||||
activeAccount={account}
|
||||
activeWallet={props.activeWallet}
|
||||
client={client}
|
||||
/>
|
||||
)}
|
||||
|
||||
{method === "crypto" && (
|
||||
<>
|
||||
{drawerScreen === "fees" && (
|
||||
<div>
|
||||
<Text size="lg" color="primaryText">
|
||||
Fees
|
||||
</Text>
|
||||
|
||||
<Spacer y="lg" />
|
||||
{swapQuote && (
|
||||
<SwapFees quote={swapQuote} align="left" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DynamicHeight>
|
||||
</Drawer>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Container
|
||||
p="lg"
|
||||
style={{
|
||||
paddingBottom: 0,
|
||||
}}
|
||||
>
|
||||
<ModalHeader
|
||||
title={
|
||||
props.buyForTx
|
||||
? `Not enough ${props.buyForTx.tokenSymbol}`
|
||||
: "Buy"
|
||||
}
|
||||
onBack={props.onBack}
|
||||
/>
|
||||
<Spacer y="lg" />
|
||||
{isMiniScreen && <Spacer y="xl" />}
|
||||
|
||||
{amountNeeded && props.buyForTx ? (
|
||||
<BuyForTxUI
|
||||
amountNeeded={String(
|
||||
formatNumber(Number(toEther(amountNeeded)), 4),
|
||||
)}
|
||||
buyForTx={props.buyForTx}
|
||||
client={client}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* To */}
|
||||
<BuyTokenInput
|
||||
value={tokenAmount}
|
||||
onChange={async (value) => {
|
||||
setHasEditedAmount(true);
|
||||
setStopUpdatingTokenAmount(true);
|
||||
setTokenAmount(value);
|
||||
}}
|
||||
token={toToken}
|
||||
chain={toChain}
|
||||
onSelectToken={() => setScreen("select-to-token")}
|
||||
client={props.client}
|
||||
hideTokenSelector={!!props.buyForTx}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
<Spacer y="md" />
|
||||
<Container px="lg">
|
||||
{!isMiniScreen && (
|
||||
<div>
|
||||
<PaymentSelection />
|
||||
<Spacer y="md" />
|
||||
|
||||
{method === "crypto" && (
|
||||
<>
|
||||
<PayWithCrypto
|
||||
value={sourceTokenAmount}
|
||||
onSelectToken={() => {
|
||||
setScreen("select-from-token");
|
||||
}}
|
||||
chain={fromChain}
|
||||
token={fromToken}
|
||||
isLoading={
|
||||
buyWithCryptoQuoteQuery.isLoading && !sourceTokenAmount
|
||||
}
|
||||
client={client}
|
||||
/>
|
||||
<SecondaryInfo
|
||||
quoteIsLoading={buyWithCryptoQuoteQuery.isLoading}
|
||||
estimatedSeconds={
|
||||
buyWithCryptoQuoteQuery.data?.swapDetails.estimated
|
||||
.durationSeconds
|
||||
}
|
||||
onViewFees={() => setDrawerScreen("fees")}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Spacer y="md" />
|
||||
|
||||
{/* Send To */}
|
||||
{!props.buyForTx && (
|
||||
<>
|
||||
<Container>
|
||||
<Text size="sm">Send To</Text>
|
||||
<Spacer y="xxs" />
|
||||
<AccountSelectorButton
|
||||
address={address}
|
||||
activeAccount={account}
|
||||
activeWallet={activeWallet}
|
||||
onClick={() => {
|
||||
setDrawerScreen("address");
|
||||
}}
|
||||
chevron
|
||||
client={client}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
<Spacer y="md" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Container flex="column" gap="md">
|
||||
{method === "crypto" && isSwapQuoteError && (
|
||||
<div>
|
||||
<Container
|
||||
flex="row"
|
||||
gap="xxs"
|
||||
center="both"
|
||||
color="danger"
|
||||
>
|
||||
<CrossCircledIcon
|
||||
width={iconSize.sm}
|
||||
height={iconSize.sm}
|
||||
/>
|
||||
<Text color="danger" size="sm">
|
||||
{getErrorMessage()}
|
||||
</Text>
|
||||
</Container>
|
||||
<Spacer y="md" />
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{method === "crypto" && (
|
||||
<>
|
||||
{switchChainRequired && (
|
||||
<Button
|
||||
fullWidth
|
||||
variant="accent"
|
||||
disabled={isMiniScreen}
|
||||
data-disabled={isMiniScreen}
|
||||
gap="sm"
|
||||
onClick={async () => {
|
||||
setIsSwitching(true);
|
||||
try {
|
||||
await switchActiveWalletChain(fromChain);
|
||||
} catch {}
|
||||
setIsSwitching(false);
|
||||
}}
|
||||
>
|
||||
{!isMiniScreen ? (
|
||||
<>
|
||||
{isSwitching && (
|
||||
<Spinner size="sm" color="accentButtonText" />
|
||||
)}
|
||||
{isSwitching ? "Switching" : "Switch Network"}
|
||||
</>
|
||||
) : (
|
||||
"Continue"
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!switchChainRequired && (
|
||||
<Button
|
||||
variant={disableContinue ? "outline" : "accent"}
|
||||
fullWidth
|
||||
data-disabled={disableContinue}
|
||||
disabled={disableContinue}
|
||||
onClick={async () => {
|
||||
if (!disableContinue) {
|
||||
setScreen("confirmation");
|
||||
}
|
||||
}}
|
||||
gap="sm"
|
||||
>
|
||||
{isNotEnoughBalance ? "Not Enough Funds" : "Continue"}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{method === "creditCard" && (
|
||||
<Button
|
||||
variant="accent"
|
||||
fullWidth
|
||||
onClick={async () => {
|
||||
setScreen("kado-iframe");
|
||||
}}
|
||||
gap="sm"
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
)}
|
||||
</Container>
|
||||
<Spacer y="lg" />
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
const ViewFeeIcon: IconFC = (props) => {
|
||||
return (
|
||||
<svg
|
||||
width={props.size}
|
||||
height={props.size}
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M9.5 1.5H2.5C1.94772 1.5 1.5 1.94772 1.5 2.5V9.5C1.5 10.0523 1.94772 10.5 2.5 10.5H9.5C10.0523 10.5 10.5 10.0523 10.5 9.5V2.5C10.5 1.94772 10.0523 1.5 9.5 1.5Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.5 7.5L7.5 4.5"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
function SecondaryInfo(props: {
|
||||
estimatedSeconds?: number | undefined;
|
||||
quoteIsLoading: boolean;
|
||||
onViewFees: () => void;
|
||||
}) {
|
||||
const { estimatedSeconds, quoteIsLoading } = props;
|
||||
|
||||
return (
|
||||
<Container
|
||||
bg="tertiaryBg"
|
||||
flex="row"
|
||||
borderColor="borderColor"
|
||||
style={{
|
||||
borderRadius: radius.md,
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
borderWidth: "1px",
|
||||
borderStyle: "solid",
|
||||
}}
|
||||
>
|
||||
<Container flex="row" center="y" gap="xxs" color="accentText" p="sm">
|
||||
<ClockIcon width={iconSize.sm} height={iconSize.sm} />
|
||||
{quoteIsLoading ? (
|
||||
<Skeleton height={fontSize.xs} width="50px" color="borderColor" />
|
||||
) : (
|
||||
<Text size="xs" color="secondaryText">
|
||||
{estimatedSeconds !== undefined
|
||||
? `~${formatSeconds(estimatedSeconds)}`
|
||||
: "--"}
|
||||
</Text>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
<FeesButton variant="secondary" onClick={props.onViewFees}>
|
||||
<Container color="accentText" flex="row" center="both">
|
||||
<ViewFeeIcon size={iconSize.sm} />
|
||||
</Container>
|
||||
<Text size="xs" color="secondaryText">
|
||||
View Fees
|
||||
</Text>
|
||||
</FeesButton>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
function BuyForTxUI(props: {
|
||||
amountNeeded: string;
|
||||
buyForTx: BuyForTx;
|
||||
client: ThirdwebClient;
|
||||
}) {
|
||||
const chainQuery = useChainQuery(props.buyForTx.tx.chain);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Spacer y="xs" />
|
||||
<Container
|
||||
flex="row"
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Text size="sm">Amount Needed</Text>
|
||||
<Container
|
||||
flex="column"
|
||||
style={{
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<Container flex="row" gap="xs" center="y">
|
||||
<Text color="primaryText" size="sm">
|
||||
{props.amountNeeded} {props.buyForTx.tokenSymbol}
|
||||
</Text>
|
||||
<TokenIcon
|
||||
chain={props.buyForTx.tx.chain}
|
||||
client={props.client}
|
||||
size="sm"
|
||||
token={NATIVE_TOKEN}
|
||||
/>
|
||||
</Container>
|
||||
<Spacer y="xxs" />
|
||||
{chainQuery.data ? (
|
||||
<Text size="sm"> {chainQuery.data.name}</Text>
|
||||
) : (
|
||||
<Skeleton height={fontSize.sm} width="50px" />
|
||||
)}
|
||||
</Container>
|
||||
</Container>
|
||||
|
||||
<Spacer y="md" />
|
||||
<Line />
|
||||
<Spacer y="md" />
|
||||
|
||||
<Container
|
||||
flex="row"
|
||||
style={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<Text size="sm">Your Balance</Text>
|
||||
<Container flex="row" gap="xs">
|
||||
<Text color="primaryText" size="sm">
|
||||
{formatNumber(Number(toEther(props.buyForTx.balance)), 4)}{" "}
|
||||
{props.buyForTx.tokenSymbol}
|
||||
</Text>
|
||||
<TokenIcon
|
||||
chain={props.buyForTx.tx.chain}
|
||||
client={props.client}
|
||||
size="sm"
|
||||
token={NATIVE_TOKEN}
|
||||
/>
|
||||
</Container>
|
||||
</Container>
|
||||
|
||||
<Spacer y="md" />
|
||||
<Line />
|
||||
<Spacer y="lg" />
|
||||
|
||||
<Text center size="sm">
|
||||
Purchase
|
||||
</Text>
|
||||
<Spacer y="xxs" />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user