Skip to content

Commit a6ff9c9

Browse files
DrakeoontowanTG
andauthored
feat: improve token selection UI, add better sorting and filtering strategy (#1588)
* feat: remove redundant code * fix: fix next playground build issues, add exact=true to bunfig * feat: implement improved token selection UI, rework balance calculation in swapkit context * feat: improve balance state calculation, improve wallet drawer ui * fix: fix hook after balance naming changes * feat: switch to built-in assetValue staticTokensMap, load tokens in the swapkit-context module * feat: add small optimisation for calculating filtered values * fix: fix createSwapKit sdk type errors * fix: fix swapkit ui type errors * chore: revert WalletConnectButton and keystore dialog changes * chore: apply changes after review * chore: revert type changes * fix: fix types * feat: improve keystore connect dialog (#1587) * fix: resolve missing dependencies issue, set exact=true in bunfig.toml * feat: set up the dialog components for keystore * feat: add tabs from shadcn/ui, improve dialog footer layout * feat: restore and refactor some of the keystore connect implementation * feat: add shadcn/ui components for implementing rich forms * feat: move keystore connection state outside of swapkit context, use react-hook-form for WalletKeystoreConnectDialog * feat: add loading states, move file input onChange handler outside of jsx * chore: reorder imports * feat: show new keystore connect dialog on keystore click * chore: remove old keystore dialog, remove dialog components outside of the scope * chore: update bun.lock * feat: tweak dialog styles to handle edge cases * feat: add missing variables, handle styling edge cases * feat: add v3 quote swap flow (#1590) * feat: remove redundant code * fix: fix next playground build issues, add exact=true to bunfig * feat: implement improved token selection UI, rework balance calculation in swapkit context * feat: improve balance state calculation, improve wallet drawer ui * fix: fix hook after balance naming changes * feat: switch to built-in assetValue staticTokensMap, load tokens in the swapkit-context module * feat: add small optimisation for calculating filtered values * fix: fix createSwapKit sdk type errors * fix: fix swapkit ui type errors * chore: revert WalletConnectButton and keystore dialog changes * chore: apply changes after review * chore: revert type changes * fix: fix types * fix: resolve missing dependencies issue, set exact=true in bunfig.toml * feat: set up the dialog components for keystore * feat: add tabs from shadcn/ui, improve dialog footer layout * feat: restore and refactor some of the keystore connect implementation * feat: add shadcn/ui components for implementing rich forms * feat: move keystore connection state outside of swapkit context, use react-hook-form for WalletKeystoreConnectDialog * feat: add loading states, move file input onChange handler outside of jsx * chore: reorder imports * feat: show new keystore connect dialog on keystore click * chore: remove old keystore dialog, remove dialog components outside of the scope * chore: update bun.lock * feat: tweak dialog styles to handle edge cases * feat: add missing variables, handle styling edge cases * feat: add setup for v3 quote and swap requets * feat: move into new way of overriding endpoints using SKConfig * feat: adjust swap flow to match API changes * chore: remove redundant code, fix smaller issues * feat: add simple localStorage form integration, remove custom apiKey field * feat: add `sk-ui-` prefix to widget's tailwindcss config, update @swapkit/ui to use prefixed classNames (#1591) * feat: update variables and tailwind config to use prefix * chore: replace tailwind classes in @swapkit/ui to match prefix * feat: set up sk-ui- prefix in tailwind config, disable preflight, update dependencies * feat: convert missing classNames to prefixed ones * chore: clean up assetValue static map export * chore: dirty fix ts issue tailwind.config.ts no in rootDir * chore: skip balance test --------- Co-authored-by: towan <towan@swapkit.dev>
1 parent e98f261 commit a6ff9c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1535
-785
lines changed

bun.lock

Lines changed: 75 additions & 61 deletions
Large diffs are not rendered by default.

bunfig.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[install]
22
linker = "isolated"
3+
exact = true
34

45
[test]
56
coverageReporter = ["text", "lcov"]

packages/helpers/package.json

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,16 @@
66
"@swapkit/tokens": "workspace:*",
77
"@swapkit/types": "workspace:*",
88
"ethers": "^6.14.0",
9-
"ts-pattern": "^5.9.0",
9+
"ts-pattern": "5.9.0",
1010
"zod": "3.25.74",
11-
"zustand": "^5.0.0"
11+
"zustand": "5.0.8"
1212
},
1313
"description": "SwapKit - Helpers",
1414
"devDependencies": {
1515
"@near-js/providers": "2.5.0",
1616
"@swapkit/toolboxes": "workspace:*",
1717
"ethers": "6.15.0",
18-
"tronweb": "6.1.0",
19-
"ts-pattern": "5.9.0",
20-
"zod": "3.25.74",
21-
"zustand": "5.0.8"
18+
"tronweb": "6.1.0"
2219
},
2320
"exports": {
2421
".": {

packages/helpers/src/api/swapkitApi/endpoints.ts

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
SKConfig,
99
SwapKitError,
1010
} from "@swapkit/helpers";
11-
11+
import { match, P } from "ts-pattern";
1212
import {
1313
type BalanceResponse,
1414
type BrokerDepositChannelParams,
@@ -24,6 +24,8 @@ import {
2424
PriceResponseSchema,
2525
type QuoteRequest,
2626
type QuoteResponse,
27+
type QuoteResponseRoute,
28+
QuoteResponseRouteItem,
2729
QuoteResponseSchema,
2830
type TokenListProvidersResponse,
2931
type TokensResponseV2,
@@ -32,12 +34,7 @@ import {
3234
type TrackingRequest,
3335
} from "./types";
3436

35-
const SKRequestClient = RequestClient.extend({
36-
dynamicHeader: () => {
37-
const { swapKit } = SKConfig.get("apiKeys");
38-
return swapKit ? { "x-api-key": swapKit } : {};
39-
},
40-
});
37+
export const SKRequestClient = RequestClient;
4138

4239
export async function getTrackerDetails(json: TrackingRequest) {
4340
const response = await SKRequestClient.post<TrackerResponse>(getApiUrl("/track"), { json });
@@ -57,6 +54,10 @@ export async function getTrackerDetails(json: TrackingRequest) {
5754
}
5855

5956
export async function getSwapQuote(json: QuoteRequest) {
57+
const { getQuote } = SKConfig.get("endpoints");
58+
59+
if (getQuote) return getQuote(json);
60+
6061
const response = await SKRequestClient.post<QuoteResponse>(getApiUrl("/quote"), { json });
6162

6263
if (response.error) {
@@ -77,6 +78,27 @@ export async function getSwapQuote(json: QuoteRequest) {
7778
}
7879
}
7980

81+
export async function getRouteWithTx(json: { routeId: string; sourceAddress: string; destinationAddress: string }) {
82+
const { getRouteWithTx } = SKConfig.get("endpoints");
83+
84+
if (getRouteWithTx) return getRouteWithTx(json);
85+
86+
const response = await SKRequestClient.post<QuoteResponseRoute>(getApiUrl("/swap"), { json });
87+
88+
try {
89+
const parsedResponse = QuoteResponseRouteItem.safeParse(response);
90+
91+
if (!parsedResponse.success) {
92+
throw new SwapKitError("api_v2_invalid_response", parsedResponse.error);
93+
}
94+
95+
return parsedResponse.data;
96+
} catch (error) {
97+
console.error(new SwapKitError("api_v2_invalid_response", error));
98+
return response;
99+
}
100+
}
101+
80102
export async function getChainBalance<T extends Chain>({
81103
chain,
82104
address,
@@ -187,9 +209,20 @@ export async function getNearDepositChannel(body: NearDepositChannelParams) {
187209
}
188210

189211
function getApiUrl(path?: `/${string}`) {
190-
const { isDev, apiUrl, devApiUrl } = SKConfig.get("envs");
191-
192-
return `${isDev ? devApiUrl : apiUrl}${path}`;
212+
const { isDev, apiUrl, devApiUrl, experimental_apiUrlQuote, experimental_apiUrlSwap } = SKConfig.get("envs");
213+
214+
const defaultUrl = `${isDev ? devApiUrl : apiUrl}${path}`;
215+
216+
return match({ experimental_apiUrlQuote, experimental_apiUrlSwap, path })
217+
.with(
218+
{ experimental_apiUrlQuote: P.string.startsWith("http"), path: "/quote" },
219+
({ experimental_apiUrlQuote, path }) => `${experimental_apiUrlQuote}${path}`,
220+
)
221+
.with(
222+
{ experimental_apiUrlSwap: P.string.startsWith("http"), path: "/swap" },
223+
({ experimental_apiUrlSwap, path }) => `${experimental_apiUrlSwap}${path}`,
224+
)
225+
.otherwise(() => defaultUrl);
193226
}
194227

195228
function evmAssetHasAddress(assetString: string) {

packages/helpers/src/api/swapkitApi/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ const QuoteResponseRouteLegItem = object({
553553
sellAsset: string().describe("Asset to sell"),
554554
});
555555

556-
const QuoteResponseRouteItem = object({
556+
export const QuoteResponseRouteItem = object({
557557
buyAsset: string().describe("Asset to buy"),
558558
destinationAddress: string().describe("Destination address"),
559559
estimatedTime: optional(EstimatedTimeSchema),
@@ -566,6 +566,7 @@ const QuoteResponseRouteItem = object({
566566
memo: optional(string().describe("Memo")),
567567
meta: RouteQuoteMetadataV2Schema,
568568
providers: array(z.enum(ProviderName)),
569+
routeId: string().describe("Route ID"),
569570
sellAmount: string().describe("Sell amount"),
570571
sellAsset: string().describe("Asset to sell"),
571572
sourceAddress: string().describe("Source address"),

packages/helpers/src/modules/assetValue.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const CASE_SENSITIVE_CHAINS: Chain[] = [Chain.Solana, Chain.Tron, Chain.Near, Ch
2222
const TC_CHAINS: Chain[] = [Chain.THORChain, Chain.Maya];
2323

2424
const staticTokensMap = new Map<
25-
TokenNames | string,
25+
TokenNames | (string & {}),
2626
{ tax?: TokenTax; decimal: number; identifier: string; logoURI?: string }
2727
>();
2828

@@ -298,6 +298,10 @@ or by passing asyncTokenLookup: true to the from() function, which will make it
298298
}
299299
return true;
300300
}
301+
302+
static get staticAssets() {
303+
return staticTokensMap;
304+
}
301305
}
302306

303307
export function getMinAmountByChain(chain: Chain) {

packages/helpers/src/modules/swapKitConfig.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "@swapkit/types";
99
import { create } from "zustand";
1010
import { useShallow } from "zustand/shallow";
11-
import type { BalanceResponse } from "../api";
11+
import type { BalanceResponse, QuoteRequest, QuoteResponse, QuoteResponseRoute } from "../api";
1212
import { WalletOption } from "../types";
1313
import type { FeeMultiplierConfig } from "./feeMultiplier";
1414

@@ -38,6 +38,8 @@ export type SKConfigIntegrations = {
3838

3939
export type CustomApiEndpoints = {
4040
getBalance: ({ chain, address }: { chain: Chain; address: string }) => Promise<BalanceResponse>;
41+
getQuote: (json: QuoteRequest) => Promise<QuoteResponse>;
42+
getRouteWithTx: (json: { routeId: string }) => Promise<QuoteResponseRoute>;
4143
};
4244

4345
const rpcUrls = AllChains.reduce(
@@ -60,6 +62,9 @@ const initialState = {
6062
envs: {
6163
apiUrl: "https://api.swapkit.dev",
6264
devApiUrl: "https://dev-api.swapkit.dev",
65+
experimental_apiKey: null as string | null,
66+
experimental_apiUrlQuote: null as string | null,
67+
experimental_apiUrlSwap: null as string | null,
6368
isDev: false,
6469
isStagenet: false,
6570
},
@@ -112,6 +117,7 @@ export const useSwapKitStore = create<SwapKitConfigStore>((set) => ({
112117
set((s) => ({
113118
apiKeys: { ...s.apiKeys, ...config?.apiKeys },
114119
chains: s.chains.concat(config?.chains || []),
120+
endpoints: { ...s.endpoints, ...config?.endpoints },
115121
envs: { ...s.envs, ...config?.envs },
116122
feeMultipliers: config?.feeMultipliers || s.feeMultipliers,
117123
integrations: { ...s.integrations, ...config?.integrations },
@@ -138,6 +144,7 @@ export const useSwapKitConfig = () =>
138144
useShallow((state) => ({
139145
apiKeys: state?.apiKeys,
140146
chains: state?.chains,
147+
endpoints: state?.endpoints,
141148
envs: state?.envs,
142149
feeMultipliers: state?.feeMultipliers,
143150
integrations: state?.integrations,

packages/sdk/src/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,14 @@ export const defaultWallets = {
114114
...walletSelectorWallet,
115115
...walletconnectWallet,
116116
...xamanWallet,
117-
};
117+
} as ReturnType<typeof createWallet>;
118118

119119
export function createSwapKit<
120-
Plugins extends ReturnType<typeof createPlugin> = typeof defaultPlugins,
121-
Wallets extends ReturnType<typeof createWallet> = typeof defaultWallets,
120+
Plugins extends ReturnType<typeof createPlugin>,
121+
Wallets extends ReturnType<typeof createWallet>,
122122
>({ config, plugins, wallets }: { config?: SKConfigState; plugins?: Plugins; wallets?: Wallets } = {}) {
123-
const mergedPlugins = { ...defaultPlugins, ...plugins } as typeof defaultPlugins & Plugins;
124-
const mergedWallets = { ...defaultWallets, ...wallets } as typeof defaultWallets & Wallets;
123+
const mergedPlugins = { ...defaultPlugins, ...plugins };
124+
const mergedWallets = { ...defaultWallets, ...wallets };
125125

126126
return SwapKit({ config: config, plugins: mergedPlugins, wallets: mergedWallets });
127127
}

packages/toolboxes/src/evm/__tests__/ethereum.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ beforeEach(async () => {
4747
});
4848

4949
describe("Ethereum toolkit", () => {
50-
test("Get Balances", async () => {
50+
test.skip("Get Balances", async () => {
5151
const balances = await context.toolbox.getBalance(testAddress);
5252
expect(balances.find((balance) => balance.symbol === "ETH")?.getBaseValue("string")).toBe("20526000000000000");
5353
expect(

packages/ui/package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"author": "swapkit-oss",
33
"dependencies": {
4+
"@hookform/resolvers": "5.2.2",
45
"@radix-ui/react-accordion": "1.2.12",
56
"@radix-ui/react-alert-dialog": "1.1.15",
67
"@radix-ui/react-checkbox": "1.3.3",
@@ -23,15 +24,16 @@
2324
"clsx": "2.1.1",
2425
"lucide-react": "0.552.0",
2526
"react": "19.1.1",
27+
"react-hook-form": "7.65.0",
2628
"sonner": "2.0.7",
27-
"tailwind-merge": "3.3.1",
29+
"tailwind-merge": "2.6.0",
2830
"tailwindcss": "3.4.18",
2931
"tailwindcss-animate": "1.0.7",
30-
"ts-pattern": "^5.9.0",
31-
"zustand": "^5.0.0"
32+
"ts-pattern": "5.9.0",
33+
"zod": "3.25.74",
34+
"zustand": "5.0.8"
3235
},
3336
"description": "SwapKit - UI",
34-
"devDependencies": { "ts-pattern": "5.9.0", "zustand": "5.0.8" },
3537
"exports": {
3638
".": {
3739
"bun": "./src/index.ts",

0 commit comments

Comments
 (0)