From c634681d1d36f7be272d285c09a832e61e64767e Mon Sep 17 00:00:00 2001 From: Ochhii Date: Mon, 2 Dec 2024 14:54:12 +0000 Subject: [PATCH 01/26] Feat/authenticate request (#1101) * add compute hash logic into api v2 requests * changeset * chore: clean up code and adds missing ske code * update logic to add apiKey header * fix merge conflicts * feat: removes api v1 support * feat: Add getGas endpoint with type validation and error handling * feat: Add API methods with key support to SwapKit client * feat: Add optional swapkitApiKey to SwapKitParams config type * refactor: Update gas rate function and hash computation logic * refactor: Compute hash only when referer is set in endpoint methods * refactor: Simplify hash computation and header generation in API endpoints * refactor: Extract common header generation logic into helper function * feat: cleans up branch and adds hydrated swapkitapi to core client * chore: changeset --------- Co-authored-by: github-actions[bot] Co-authored-by: towan <95243956+towanTG@users.noreply.github.com> --- .changeset/chilled-beds-check.md | 5 + .changeset/lazy-scissors-play.md | 9 + .changeset/witty-seahorses-check.md | 5 + .../plugins/thorchain/src/getSwapParams.ts | 81 --- packages/plugins/thorchain/src/index.ts | 1 - packages/plugins/thorchain/src/tcPlugin.ts | 174 +----- packages/plugins/thorchain/src/types.ts | 9 - packages/swapkit/api/src/index.ts | 3 - .../swapkit/api/src/swapkitApi/endpoints.ts | 198 +++++- packages/swapkit/api/src/swapkitApi/types.ts | 12 + .../__tests__/requestClient.test.ts | 13 - .../swapkit/api/src/thorswapApi/endpoints.ts | 94 --- packages/swapkit/api/src/thorswapApi/types.ts | 582 ------------------ packages/swapkit/core/src/client.ts | 35 +- .../helpers/src/modules/swapKitError.ts | 1 + .../swapkit/helpers/src/types/commonTypes.ts | 19 +- .../cosmos/src/toolbox/BaseCosmosToolbox.ts | 6 +- playgrounds/vite/src/swapKitClient.ts | 1 - 18 files changed, 265 insertions(+), 983 deletions(-) create mode 100644 .changeset/chilled-beds-check.md create mode 100644 .changeset/lazy-scissors-play.md create mode 100644 .changeset/witty-seahorses-check.md delete mode 100644 packages/plugins/thorchain/src/getSwapParams.ts delete mode 100644 packages/swapkit/api/src/thorswapApi/__tests__/requestClient.test.ts delete mode 100644 packages/swapkit/api/src/thorswapApi/endpoints.ts delete mode 100644 packages/swapkit/api/src/thorswapApi/types.ts diff --git a/.changeset/chilled-beds-check.md b/.changeset/chilled-beds-check.md new file mode 100644 index 000000000..030d4574d --- /dev/null +++ b/.changeset/chilled-beds-check.md @@ -0,0 +1,5 @@ +--- +"@swapkit/api": minor +--- + +Added x-payload-hash logic and update api v2 requests to include this header diff --git a/.changeset/lazy-scissors-play.md b/.changeset/lazy-scissors-play.md new file mode 100644 index 000000000..bdd69dc9f --- /dev/null +++ b/.changeset/lazy-scissors-play.md @@ -0,0 +1,9 @@ +--- +"@swapkit/plugin-thorchain": major +"@swapkit/core": major +"@swapkit/api": major +"@swapkit/toolbox-cosmos": minor +"@swapkit/helpers": minor +--- + +Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. diff --git a/.changeset/witty-seahorses-check.md b/.changeset/witty-seahorses-check.md new file mode 100644 index 000000000..d41ac77ae --- /dev/null +++ b/.changeset/witty-seahorses-check.md @@ -0,0 +1,5 @@ +--- +"@swapkit/helpers": patch +--- + +Adds new SwapKitError Code diff --git a/packages/plugins/thorchain/src/getSwapParams.ts b/packages/plugins/thorchain/src/getSwapParams.ts deleted file mode 100644 index 80ee6bda8..000000000 --- a/packages/plugins/thorchain/src/getSwapParams.ts +++ /dev/null @@ -1,81 +0,0 @@ -import type { QuoteRoute } from "@swapkit/api"; -import { - type AGG_CONTRACT_ADDRESS, - SwapKitError, - lowercasedGenericAbiMappings, -} from "@swapkit/helpers"; - -type SwapInParams = { - calldata: QuoteRoute["calldata"]; - recipient: string; - streamSwap?: boolean; - contractAddress: AGG_CONTRACT_ADDRESS; - toChecksumAddress: (address: string) => string; -}; - -export const getSwapInParams = ({ - streamSwap, - contractAddress, - recipient, - toChecksumAddress, - calldata, -}: SwapInParams) => { - const isGeneric = !!lowercasedGenericAbiMappings[contractAddress.toLowerCase()]; - const { - amount, - amountOutMin = "", - data = "", - deadline, - memo, - router, - memoStreamingSwap, - tcMemo, - tcRouter, - tcVault, - vault, - token, - } = calldata; - - if (isGeneric && !router) { - throw new SwapKitError({ errorKey: "thorchain_swapin_router_required", info: calldata }); - } - - /** - * Data structure for contract calls - * GENERIC: tcRouter, tcVault, tcMemo, token, amount, router, data, deadline - * ETH_UNISWAP: tcRouter, tcVault, tcMemo, token, amount, amountOutMin, deadline - * AVAX_PANGOLIN: tcRouter, tcVault, tcMemo, token, amount, amountOutMin, deadline - * AVAX_WOOFI: router, vault, memo, token, amount, amountOutMin, deadline - */ - - const baseMemo = tcMemo || memo; - const transactionMemo = streamSwap ? memoStreamingSwap || baseMemo : baseMemo; - - if (!(tcVault || vault)) { - throw new SwapKitError({ errorKey: "thorchain_swapin_vault_required", info: calldata }); - } - if (!(tcRouter || router)) { - throw new SwapKitError({ errorKey: "thorchain_swapin_router_required", info: calldata }); - } - if (!transactionMemo) { - throw new SwapKitError({ errorKey: "thorchain_swapin_memo_required", info: calldata }); - } - if (!token) { - throw new SwapKitError({ errorKey: "thorchain_swapin_token_required", info: calldata }); - } - - const baseParams = [ - // v2 contracts don't have tcVault, tcRouter, tcMemo but vault, router, memo - toChecksumAddress((tcRouter || router) as string), - toChecksumAddress((tcVault || vault) as string), - transactionMemo.replace("{recipientAddress}", recipient), - toChecksumAddress(token), - amount, - ]; - - const contractParams = isGeneric - ? [toChecksumAddress(router as string), data, deadline] - : [amountOutMin, deadline]; - - return [...baseParams, ...contractParams]; -}; diff --git a/packages/plugins/thorchain/src/index.ts b/packages/plugins/thorchain/src/index.ts index 62459d19b..0359afe53 100644 --- a/packages/plugins/thorchain/src/index.ts +++ b/packages/plugins/thorchain/src/index.ts @@ -1,4 +1,3 @@ export * from "./tcPlugin"; export * from "./mayaPlugin"; -export * from "./getSwapParams"; export { validateAddressType } from "./shared"; diff --git a/packages/plugins/thorchain/src/tcPlugin.ts b/packages/plugins/thorchain/src/tcPlugin.ts index c3dd2e96b..b52076e3f 100644 --- a/packages/plugins/thorchain/src/tcPlugin.ts +++ b/packages/plugins/thorchain/src/tcPlugin.ts @@ -1,19 +1,12 @@ -import type { QuoteResponseRoute, QuoteRoute } from "@swapkit/api"; +import type { QuoteResponseRoute } from "@swapkit/api"; import { - type AGG_CONTRACT_ADDRESS, - AGG_SWAP, AssetValue, Chain, - ChainToChainId, type EVMChain, type ErrorKeys, - FeeOption, MemoType, ProviderName, - SWAP_IN, - SWAP_OUT, SwapKitError, - SwapKitNumber, type SwapKitPluginParams, type SwapParams, TCAvalancheDepositABI, @@ -21,19 +14,11 @@ import { TCEthereumVaultAbi, type UTXOChain, getMemoForLoan, - lowercasedContractAbiMapping, } from "@swapkit/helpers"; import { basePlugin } from "./basePlugin"; -import { getSwapInParams } from "./getSwapParams"; import { prepareTxParams, validateAddressType } from "./shared"; -import type { - AddLiquidityParams, - CoreTxParams, - CreateLiquidityParams, - LoanParams, - SwapWithRouteParams, -} from "./types"; +import type { AddLiquidityParams, CoreTxParams, CreateLiquidityParams, LoanParams } from "./types"; type SupportedChain = EVMChain | Chain.THORChain | UTXOChain | Chain.Cosmos; @@ -163,160 +148,7 @@ function plugin({ getWallet, stagenet = false }: SwapKitPluginParams) { }); } - function swap({ route, ...rest }: SwapParams<"thorchain", QuoteResponseRoute>) { - if (!route) throw new SwapKitError("core_swap_invalid_params"); - - const isV2Route = "legs" in route; - - if (isV2Route) { - return swapV2({ route, ...rest }); - } - - return swapV1({ route, ...rest } as SwapWithRouteParams); - } - - // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: remove - async function swapV1(swapParams: SwapWithRouteParams) { - if (!("route" in swapParams)) throw new SwapKitError("core_swap_invalid_params"); - - const route = swapParams.route as QuoteRoute; - - const { streamSwap, recipient, feeOptionKey } = swapParams as SwapWithRouteParams; - const { - meta: { quoteMode }, - // evmTransactionDetails: contractCallParams, - } = route; - const evmChain = quoteMode.startsWith("ERC20-") - ? Chain.Ethereum - : quoteMode.startsWith("ARC20-") - ? Chain.Avalanche - : quoteMode.startsWith("BEP20-") - ? Chain.BinanceSmartChain - : undefined; - - if (!route.complete) throw new SwapKitError("core_swap_route_not_complete"); - - // TODO enable when BE is ready - // if (contractCallParams && evmChain) { - // const walletMethods = this.connectedWallets[evmChain]; - - // if (!walletMethods?.call) { - // throw new SwapKitError('core_wallet_connection_not_found'); - // } - - // const { contractAddress, contractMethod, contractParams, contractParamsStreaming } = - // contractCallParams; - - // if (!(streamSwap ? contractParamsStreaming : contractParams)) { - // throw new SwapKitError('core_swap_route_transaction_not_found'); - // } - - // return await walletMethods.call({ - // contractAddress, - // abi: lowercasedContractAbiMapping[contractAddress.toLowerCase()], - // funcName: contractMethod, - // funcParams: streamSwap ? contractParamsStreaming : contractParams, - // }); - // } - - if (AGG_SWAP.includes(quoteMode) && evmChain) { - const wallet = getWallet(evmChain); - - if (!wallet?.sendTransaction) { - throw new SwapKitError("core_wallet_connection_not_found"); - } - - const transaction = streamSwap ? route?.streamingSwap?.transaction : route?.transaction; - - if (!transaction) { - throw new SwapKitError("core_swap_route_transaction_not_found"); - } - - const { data, from, to, value } = route.transaction; - const params = { - data, - from, - to: to.toLowerCase(), - chainId: BigInt(ChainToChainId[evmChain]), - value: value ? BigInt(value) : 0n, - }; - - return wallet.sendTransaction(params, feeOptionKey || FeeOption.Average); - } - - if (SWAP_OUT.includes(quoteMode)) { - if (!route.calldata.fromAsset) { - throw new SwapKitError("core_swap_asset_not_recognized"); - } - - const asset = await AssetValue.from({ - asset: route.calldata.fromAsset, - asyncTokenLookup: true, - }); - if (!asset) { - throw new SwapKitError("core_swap_asset_not_recognized"); - } - - const { address: recipient } = await getInboundDataByChain(asset.chain); - const { - contract: router, - calldata: { expiration, amountIn, memo, memoStreamingSwap }, - } = route; - - const assetValue = asset.add(SwapKitNumber.fromBigInt(BigInt(amountIn), asset.decimal)); - const swapMemo = (streamSwap ? memoStreamingSwap || memo : memo) as string; - - return deposit({ - expiration, - assetValue, - memo: swapMemo, - feeOptionKey, - router, - recipient, - }); - } - - if (SWAP_IN.includes(quoteMode) && evmChain) { - const { calldata, contract: contractAddress } = route; - if (!contractAddress) { - throw new SwapKitError("core_swap_contract_not_found"); - } - - const wallet = getWallet(evmChain); - const from = wallet.address; - - if (!from) { - throw new SwapKitError("core_wallet_connection_not_found"); - } - - const { getProvider, toChecksumAddress } = await import("@swapkit/toolbox-evm"); - const provider = getProvider(evmChain); - const abi = lowercasedContractAbiMapping[contractAddress.toLowerCase()]; - - if (!abi) { - throw new SwapKitError("core_swap_contract_not_supported", { contractAddress }); - } - - const contract = wallet.createContract(contractAddress, abi, provider); - - const tx = await contract.getFunction("swapIn").populateTransaction( - ...getSwapInParams({ - streamSwap, - toChecksumAddress, - contractAddress: contractAddress as AGG_CONTRACT_ADDRESS, - recipient, - calldata, - }), - { from }, - ); - - return wallet.sendTransaction(tx, feeOptionKey || FeeOption.Average); - } - - throw new SwapKitError("core_swap_quote_mode_not_supported", { quoteMode }); - } - - async function swapV2({ route, feeOptionKey }: SwapParams<"thorchain", QuoteResponseRoute>) { + async function swap({ route, feeOptionKey }: SwapParams<"thorchain", QuoteResponseRoute>) { if (!route) throw new SwapKitError("core_swap_invalid_params"); const { memo, expiration, targetAddress } = route; diff --git a/packages/plugins/thorchain/src/types.ts b/packages/plugins/thorchain/src/types.ts index 7ce51a380..a31d39edc 100644 --- a/packages/plugins/thorchain/src/types.ts +++ b/packages/plugins/thorchain/src/types.ts @@ -1,4 +1,3 @@ -import type { QuoteRoute } from "@swapkit/api"; import type { AssetValue, CosmosWallets, @@ -60,14 +59,6 @@ export type NodeActionParams = { address: string } & ( | { type: MemoType.LEAVE; assetValue?: undefined } ); -export type SwapWithRouteParams = { - recipient: string; - route: QuoteRoute; - feeOptionKey?: FeeOption; - quoteId?: string; - streamSwap?: boolean; -}; - export type SavingsParams = { assetValue: AssetValue; memo?: string } & ( | { type: "add"; percent?: undefined } | { type: "withdraw"; percent: number } diff --git a/packages/swapkit/api/src/index.ts b/packages/swapkit/api/src/index.ts index 0ac434bbd..a55b387df 100644 --- a/packages/swapkit/api/src/index.ts +++ b/packages/swapkit/api/src/index.ts @@ -2,10 +2,8 @@ import * as microgardEndpoints from "./microgard/endpoints"; import { mayachainMidgard, thorchainMidgard } from "./midgard/endpoints"; import * as swapkitApiEndpoints from "./swapkitApi/endpoints"; import * as thornodeEndpoints from "./thornode/endpoints"; -import * as thorswapApiEndpoints from "./thorswapApi/endpoints"; import * as thorswapStaticEndpoints from "./thorswapStatic/endpoints"; -export * from "./thorswapApi/types"; export * from "./microgard/types"; export * from "./thorswapStatic/types"; export * from "./thornode/types"; @@ -14,7 +12,6 @@ export * from "./swapkitApi/types"; export const SwapKitApi = { ...microgardEndpoints, ...thornodeEndpoints, - ...thorswapApiEndpoints, ...swapkitApiEndpoints, ...thorswapStaticEndpoints, thorchainMidgard, diff --git a/packages/swapkit/api/src/swapkitApi/endpoints.ts b/packages/swapkit/api/src/swapkitApi/endpoints.ts index 70df83d6f..d4aa3d101 100644 --- a/packages/swapkit/api/src/swapkitApi/endpoints.ts +++ b/packages/swapkit/api/src/swapkitApi/endpoints.ts @@ -1,5 +1,9 @@ +import crypto from "crypto"; import { ProviderName, RequestClient, SwapKitError } from "@swapkit/helpers"; + import { + type GasResponse, + GasResponseSchema, type PriceRequest, type PriceResponse, PriceResponseSchema, @@ -11,7 +15,6 @@ import { type TrackerParams, type TrackerResponse, } from "./types"; - const baseUrl = "https://api.swapkit.dev"; const baseUrlDev = "https://dev-api.swapkit.dev"; @@ -19,21 +22,104 @@ function getBaseUrl(isDev?: boolean) { return isDev ? baseUrlDev : baseUrl; } -export function getTrackerDetails(payload: TrackerParams, apiKey?: string) { - return RequestClient.post(`${getBaseUrl()}/track`, { +const getAuthHeaders = (hash?: string, apiKey?: string, referer?: string) => ({ + ...(apiKey && !hash ? { "x-api-key": apiKey } : {}), + ...(hash && referer ? { "x-payload-hash": hash, referer } : {}), +}); + +export const computeHash = ( + hashParams: + | { + apiKey: string; + method: "POST"; + payload: any; + } + | { + apiKey: string; + method: "GET"; + url: string; + }, +): string => { + const { method } = hashParams; + switch (method) { + case "POST": + return computeHashForPost(hashParams); + case "GET": + return computeHashForGet(hashParams); + default: + throw new SwapKitError("api_v2_invalid_method_key_hash", { + message: `Invalid method: ${method}`, + }); + } +}; + +export const computeHashForGet = ({ + url, + apiKey, +}: { + url: string; + apiKey: string; +}): string => { + return crypto.createHash("sha256").update(`${url}${apiKey}`, "utf8").digest("hex"); +}; + +export const computeHashForPost = ({ + apiKey, + payload, +}: { + apiKey: string; + payload: any; +}): string => { + const normalizedBody = JSON.stringify(payload); + return crypto.createHash("sha256").update(`${normalizedBody}${apiKey}`, "utf8").digest("hex"); +}; + +export function getTrackerDetails(payload: TrackerParams, apiKey?: string, referer?: string) { + const url = `${getBaseUrl()}/track`; + const hash = + referer && apiKey + ? computeHash({ + method: "POST", + apiKey, + payload, + }) + : undefined; + return RequestClient.post(url, { json: payload, - headers: apiKey ? { "x-api-key": apiKey } : {}, + headers: getAuthHeaders(hash, apiKey, referer), }); } -export async function getSwapQuoteV2( +/** + * @deprecated Use getSwapQuote instead + */ +export function getSwapQuoteV2( searchParams: QuoteRequest, isDev?: T, apiKey?: string, + referer?: string, ) { - const response = await RequestClient.post(`${getBaseUrl(isDev)}/quote`, { + return getSwapQuote(searchParams, isDev, apiKey, referer); +} + +export async function getSwapQuote( + searchParams: QuoteRequest, + isDev?: T, + apiKey?: string, + referer?: string, +) { + const url = `${getBaseUrl(isDev)}/quote`; + const hash = + referer && apiKey + ? computeHash({ + method: "POST", + apiKey: apiKey, + payload: searchParams, + }) + : undefined; + const response = await RequestClient.post(url, { json: searchParams, - headers: apiKey ? { "x-api-key": apiKey } : {}, + headers: getAuthHeaders(hash, apiKey, referer), }); if (response.error) { @@ -55,22 +141,71 @@ export async function getSwapQuoteV2( } } -export function getTokenListProvidersV2(isDev = false, apiKey?: string) { - return RequestClient.get(`${getBaseUrl(isDev)}/providers`, { - headers: apiKey ? { "x-api-key": apiKey } : {}, +export function getTokenListProvidersV2(isDev = false, apiKey?: string, referer?: string) { + const url = `${getBaseUrl(isDev)}/providers`; + const hash = + referer && apiKey + ? computeHash({ + method: "GET", + apiKey, + url, + }) + : undefined; + return RequestClient.get(url, { + headers: getAuthHeaders(hash, apiKey, referer), }); } -export function getTokenListV2(provider: ProviderName, isDev = false, apiKey?: string) { - return RequestClient.get(`${getBaseUrl(isDev)}/tokens?provider=${provider}`, { - headers: apiKey ? { "x-api-key": apiKey } : {}, +/** + * @deprecated Use getTokenList instead + */ +export function getTokenListV2( + provider: ProviderName, + isDev = false, + apiKey?: string, + referer?: string, +) { + return getTokenList(provider, isDev, apiKey, referer); +} + +export function getTokenList( + provider: ProviderName, + isDev = false, + apiKey?: string, + referer?: string, +) { + const url = `${getBaseUrl(isDev)}/tokens?provider=${provider}`; + const hash = + referer && apiKey + ? computeHash({ + method: "GET", + apiKey, + url, + }) + : undefined; + return RequestClient.get(url, { + headers: getAuthHeaders(hash, apiKey, referer), }); } -export async function getPrice(body: PriceRequest, isDev = false, apiKey?: string) { - const response = await RequestClient.post(`${getBaseUrl(isDev)}/price`, { +export async function getPrice( + body: PriceRequest, + isDev = false, + apiKey?: string, + referer?: string, +) { + const url = `${getBaseUrl(isDev)}/price`; + const hash = + referer && apiKey + ? computeHash({ + method: "POST", + apiKey, + payload: body, + }) + : undefined; + const response = await RequestClient.post(url, { json: body, - headers: apiKey ? { "x-api-key": apiKey } : {}, + headers: getAuthHeaders(hash, apiKey, referer), }); try { @@ -86,11 +221,40 @@ export async function getPrice(body: PriceRequest, isDev = false, apiKey?: strin } } +export async function getGasRate(isDev = false, apiKey?: string, referer?: string) { + const url = `${getBaseUrl(isDev)}/gas`; + const hash = + referer && apiKey + ? computeHash({ + method: "GET", + apiKey, + url, + }) + : undefined; + + const response = await RequestClient.get(url, { + headers: getAuthHeaders(hash, apiKey, referer), + }); + + try { + const parsedResponse = GasResponseSchema.safeParse(response); + + if (!parsedResponse.success) { + throw new SwapKitError("api_v2_invalid_response", parsedResponse.error); + } + + return parsedResponse.data; + } catch (error) { + throw new SwapKitError("api_v2_invalid_response", error); + } +} + // TODO update this once the trading pairs are supported by BE api export async function getTokenTradingPairs( providers: ProviderName[], isDev = false, apiKey?: string, + referer?: string, ) { const tradingPairs = new Map< string, @@ -103,7 +267,7 @@ export async function getTokenTradingPairs( if (!providers.length) return tradingPairs; const providerRequests = providers.map(async (provider) => { - const tokenList = await getTokenListV2(provider, isDev, apiKey); + const tokenList = await getTokenListV2(provider, isDev, apiKey, referer); return tokenList; }); diff --git a/packages/swapkit/api/src/swapkitApi/types.ts b/packages/swapkit/api/src/swapkitApi/types.ts index 099f79276..f5be8cdec 100644 --- a/packages/swapkit/api/src/swapkitApi/types.ts +++ b/packages/swapkit/api/src/swapkitApi/types.ts @@ -682,3 +682,15 @@ export const QuoteResponseSchema = z.object({ export type QuoteResponse = z.infer; export type QuoteResponseRoute = z.infer; export type QuoteResponseRouteLeg = z.infer; + +export const GasResponseSchema = z.array( + z.object({ + id: z.number(), + chainId: z.string(), + value: z.string(), + unit: z.string(), + createdAt: z.string(), + }), +); + +export type GasResponse = z.infer; diff --git a/packages/swapkit/api/src/thorswapApi/__tests__/requestClient.test.ts b/packages/swapkit/api/src/thorswapApi/__tests__/requestClient.test.ts deleted file mode 100644 index ec7007829..000000000 --- a/packages/swapkit/api/src/thorswapApi/__tests__/requestClient.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { APIV1RequestClient } from "../endpoints"; - -describe("ApiV1 error handling", () => { - test("Expected error", async () => { - const expectedError = await APIV1RequestClient.get( - "https://api.thorswap.finance/aggregator/tokens/quote?sellAsset=ETH.00-0X881BA05DE1E78F549CC63A8F6CABB1D4AD32250D&sellAmount=1.12&buyAsset=ETH.ETH&senderAddress=0x494447b317d2ee41d4c02600edb7c2193b2c9085&recipientAddress=0x494447b317d2ee41d4c02600edb7c2193b2c9085&slippage=3", - ); - - expect(expectedError).toHaveProperty("status", 400); - expect(expectedError).toHaveProperty("identifier", "REQUEST_PARAMETER_ERROR-1003-2012"); - }); -}); diff --git a/packages/swapkit/api/src/thorswapApi/endpoints.ts b/packages/swapkit/api/src/thorswapApi/endpoints.ts deleted file mode 100644 index e67438ba5..000000000 --- a/packages/swapkit/api/src/thorswapApi/endpoints.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { RequestClient } from "@swapkit/helpers"; - -import { - ApiV1ErrorSchema, - type BorrowParams, - type BorrowResponse, - type CachedPrice, - type CachedPricesParams, - type GasPriceInfo, - type LendingAssetItem, - type LoansParams, - type LoansResponse, - type QuoteParams, - type QuoteResponseV1, - type RepayParams, - type RepayResponse, - type TokenListProvidersResponseV1, - type TxnResponse, -} from "./types"; - -const baseUrlV1 = "https://api.thorswap.finance"; - -export const APIV1RequestClient = RequestClient.extend({ - responseHandler: (response) => { - try { - const errorBody = ApiV1ErrorSchema.parse(response); - return errorBody; - } catch (_error) { - return response; - } - }, -}); - -export function getCachedPrices({ tokens, ...options }: CachedPricesParams) { - const body = new URLSearchParams(); - const filteredTokens = tokens.filter( - (token, index, sourceArr) => sourceArr.findIndex((t) => t === token) === index, - ); - - for (const token of filteredTokens) { - body.append("tokens", JSON.stringify(token)); - } - - if (options.metadata) body.append("metadata", "true"); - if (options.lookup) body.append("lookup", "true"); - if (options.sparkline) body.append("sparkline", "true"); - - return APIV1RequestClient.post(`${baseUrlV1}/tokenlist/cached-price`, { - body: body.toString(), - headers: { "Content-Type": "application/x-www-form-urlencoded" }, - }); -} - -export function getSwapQuote(searchParams: QuoteParams) { - return APIV1RequestClient.get(`${baseUrlV1}/aggregator/tokens/quote`, { - searchParams, - }); -} - -export function getBorrowQuote(searchParams: BorrowParams) { - return APIV1RequestClient.get(`${baseUrlV1}/aggregator/lending/borrow`, { - searchParams, - }); -} - -export function getRepayQuote(searchParams: RepayParams) { - return APIV1RequestClient.get(`${baseUrlV1}/aggregator/lending/repay`, { - searchParams, - }); -} - -export function getLendingAssets() { - return RequestClient.get(`${baseUrlV1}/aggregator/lending/assets`); -} - -export function getLoans(searchParams: LoansParams) { - return RequestClient.get(`${baseUrlV1}/aggregator/lending/loans`, { - searchParams, - }); -} - -export function getGasRates() { - return RequestClient.get(`${baseUrlV1}/resource-worker/gasPrice/getAll`); -} - -export function getTxnDetails(txHash: string) { - return RequestClient.get(`${baseUrlV1}/apiusage/v2/txn`, { - searchParams: { txHash }, - }); -} - -export function getTokenListProviders() { - return RequestClient.get(`${baseUrlV1}/tokenlist/providers`); -} diff --git a/packages/swapkit/api/src/thorswapApi/types.ts b/packages/swapkit/api/src/thorswapApi/types.ts deleted file mode 100644 index 785ab0427..000000000 --- a/packages/swapkit/api/src/thorswapApi/types.ts +++ /dev/null @@ -1,582 +0,0 @@ -import type { Chain, LedgerErrorCode, QuoteMode } from "@swapkit/helpers"; -import { z } from "zod"; - -export type FeeType = "AFFILIATE" | "LIQUIDITY" | "INBOUND" | "OUTBOUND" | "NETWORK"; - -export type LoansParams = { address: string; asset: string }; - -export type LoansResponse = { - owner: string; - asset: string; - debtIssued: string; - debtRepaid: string; - debtCurrent: string; - collateralCurrent: string; - collateralDeposited: string; - collateralWithdrawn: string; - lastOpenHeight: number; - ltvPercentage: string; -}; - -export type LendingAssetItem = { - asset: string; - assetDepthAssetAmount: string; - runeDepthAssetAmount: string; - loanCr: string; - loanStatus: "GREEN" | "YELLOW" | "RED"; - loanCollateral: string; - derivedDepthPercentage: string; - filledPercentage: string; - lendingAvailable: boolean; - ltvPercentage: string; -}; - -export type StreamingSwapDetails = { - completed: number | null; - total: number | null; - refunded: number | null; - progress: StreamingSwapProgressStatus[] | null; -}; - -export type TxTrackerLeg = { - hash?: string; - chain: Chain; - provider?: string; - txnType?: TransactionType; - - // transaction details - fromAsset?: string; - fromAssetImage?: string; - toAsset?: string; - toAssetImage?: string; - fromAmount?: string; - toAmount?: string; - toAmountLimit?: string; - startTimestamp?: number | null; // null before this leg has started - updateTimestamp?: number | null; // timestamp of last update - endTimestamp?: number | null; // null before this leg has ended - estimatedEndTimestamp?: number | null; // null before this leg has started - estimatedDuration?: number | null; // null before this leg has started - status?: TxStatus; - waitingFor?: string; - streamingSwapDetails?: StreamingSwapDetails; -}; - -export type TxTrackerDetails = { - quoteId: string; - firstTransactionHash: string; - currentLegIndex: number; - legs: TxTrackerLeg[]; - status?: TxStatus; - startTimestamp?: number | null; - estimatedDuration?: number | null; - isStreamingSwap?: boolean; -}; - -export type QuoteParams = { - affiliateAddress?: string; - affiliateBasisPoints?: string; - buyAsset: string; - isAffiliateFeeFlat?: string; - recipientAddress?: string; - sellAmount: string; - sellAsset: string; - senderAddress?: string; - slippage: string; -}; - -export type QuoteRoute = { - approvalTarget?: string; - approvalToken?: string; - calldata: Calldata; - complete?: boolean; - contract?: string; - contractInfo: string; - contractMethod?: string; - estimatedTime: number; - evmTransactionDetails?: EVMTransactionDetailsV1; - expectedOutput: string; - expectedOutputMaxSlippage: string; - expectedOutputMaxSlippageUSD: string; - expectedOutputUSD: string; - fees: { - [key in Chain]: Array<{ - type: string; - asset: string; - networkFee: number; - networkFeeUSD: number; - affiliateFee: number; - affiliateFeeUSD: number; - totalFee: number; - totalFeeUSD: number; - isOutOfPocket: boolean; - slipFee?: number; - slipFeeUSD?: number; - }>; - }; - inboundAddress: string; - index: number; - isPreferred?: boolean; - meta: Meta; - optimal: boolean; - path: string; - providers: string[]; - subProviders: string[]; - swaps: { - [key: string]: Array< - Array<{ - from: string; - to: string; - toTokenAddress: string; - parts: { provider: string; percentage: number }[]; - }> - >; - }; - targetAddress: string; - timeEstimates?: TimeEstimates; - transaction?: any; - streamingSwap?: { - estimatedTime: number; - fees: QuoteRoute["fees"]; - expectedOutput: string; - expectedOutputMaxSlippage: string; - expectedOutputUSD: string; - expectedOutputMaxSlippageUSD: string; - savingsInAsset: string; - savingsInUSD: string; - maxQuantity: number; - maxIntervalForMaxQuantity: number; - transaction?: any; - }; -}; - -export type RepayParams = { - repayAsset: string; - collateralAsset: string; - amountPercentage: string; - senderAddress: string; - collateralAddress: string; - affiliateBasisPoints: string; - affiliateAddress: string; -}; - -export type RepayStreamingSwap = { - inboundAddress: string; - outboundDelayBlocks: number; - outboundDelaySeconds: number; - fees: QuoteRoute["fees"]; - router: string; - expiry: number; - memo: string; - expectedAmountOut: string; - expectedCollateralWithdrawn: string; - expectedDebtRepaid: string; - repayAssetAmount: string; - repayAssetAmountUSD: string; - estimatedTime?: number; -}; - -export type RepayResponse = - | ApiV1Error - | { - inboundAddress: string; - inboundConfirmationBlocks: number; - inboundConfirmationSeconds: number; - outboundDelayBlocks: number; - outboundDelaySeconds: number; - fees: { asset: string; liquidity: string; totalBps: number }; - expiry: number; - warning?: string; - notes?: string; - dustThreshold: string; - memo: string; - expectedAmountOut: string; - expectedCollateralWithdrawn: string; - expectedDebtRepaid: string; - collateralCurrent: string; - repayAssetAmount: string; - repayAssetAmountUSD: string; - streamingSwap?: RepayStreamingSwap; - estimatedTime?: number; - }; - -export type BorrowParams = { - assetIn: string; - assetOut: string; - slippage: string; - amount: string; - senderAddress: string; - recipientAddress: string; -}; - -export type BorrowCalldata = { - amountIn: string; - amountOutMin: string; - fromAsset: string; - memo: string; - memoStreamingSwap?: string; - recipientAddress: string; - toAddress: string; - token: string; -}; - -export type BorrowStreamingSwap = { - estimatedTime: number; - expectedCollateralDeposited: string; - expectedDebtIssued: string; - expectedOutput: string; - expectedOutputMaxSlippage: string; - expectedOutputMaxSlippageUSD: string; - expectedOutputUSD: string; - fees: QuoteRoute["fees"]; - memo: string; -}; - -export type BorrowResponse = - | ApiV1Error - | { - amountIn: string; - amountOut: string; - amountOutMin: string; - calldata: BorrowCalldata; - complete: boolean; - estimatedTime: number; - expectedCollateralDeposited: string; - expectedDebtIssued: string; - expectedOutput: string; - expectedOutputMaxSlippage: string; - expectedOutputMaxSlippageUSD: string; - expectedOutputUSD: string; - fees: QuoteRoute["fees"]; - fromAsset: string; - memo: string; - recipientAddress: string; - route: { - meta: { thornodeMeta: { inboundConfirmationSeconds: number; outboundDelay: number } }; - }; - streamingSwap?: BorrowStreamingSwap; - swaps: QuoteRoute["swaps"]; - targetAddress: string; - toAsset: string; - }; - -export type EVMTransactionDetailsV1 = { - approvalSpender?: string; - approvalToken?: string; // not set in case of gas asset - contractAddress: string; - contractMethod: string; - contractParams: string[]; - contractParamsNames: string[]; - contractParamsStreaming: string[]; -}; - -export type TimeEstimates = { - swapMs: number; - inboundMs?: number; - outboundMs?: number; - streamingMs?: number; -}; - -export type TxnResponse = { - result: TxTrackerDetails; - done: boolean; - status: TxStatus; - error?: { message: string }; -}; - -export type CachedPricesParams = { - tokens: { identifier: string }[]; - metadata?: "true" | "false"; - lookup?: "true" | "false"; - sparkline?: "true" | "false"; -}; - -export type CachedPrice = { - identifier: string; - price_usd: number; - cg?: { - id?: string; - name?: string; - market_cap?: number; - total_volume?: number; - price_change_24h_usd?: number; - price_change_percentage_24h_usd?: number; - sparkline_in_7d?: string; - timestamp?: number; - }; -}; - -export type TokenListProvidersResponseV1 = Array<{ - provider: string; - nbTokens: number; -}>; - -export type GasPriceInfo = { - asset: string; - units: string; - gas: number; - chainId: string; - gasAsset: number; -}; - -export enum TransactionType { - // Old quote mode - SWAP_TC_TO_TC = "SWAP:TC-TC", - SWAP_ETH_TO_TC = "SWAP:ERC20-TC", - SWAP_TC_TO_ETH = "SWAP:TC-ERC20", - SWAP_ETH_TO_ETH = "SWAP:ERC20-ERC20", - // Old quote mode: AVAX - SWAP_AVAX_TO_TC = "SWAP:AVAX-TC", - SWAP_TC_TO_AVAX = "SWAP:TC-AVAX", - SWAP_AVAX_TO_AVAX = "SWAP:AVAX-AVAX", - SWAP_ETH_TO_AVAX = "SWAP:ETH-AVAX", - SWAP_AVAX_TO_ETH = "SWAP:AVAX-ETH", - // ATOM - SWAP_TC_TO_GAIA = "SWAP:TC-GAIA", - SWAP_GAIA_TO_TC = "SWAP:GAIA-TC", - // BTC - SWAP_TC_TO_BTC = "SWAP:TC-BTC", - SWAP_BTC_TO_TC = "SWAP:BTC-TC", - // BCH - SWAP_TC_TO_BCH = "SWAP:TC-BCH", - SWAP_BCH_TO_TC = "SWAP:BCH-TC", - // LTC - SWAP_TC_TO_LTC = "SWAP:TC-LTC", - SWAP_LTC_TO_TC = "SWAP:LTC-TC", - // DOGE - SWAP_TC_TO_DOGE = "SWAP:TC-DOGE", - SWAP_DOGE_TO_TC = "SWAP:DOGE-TC", - // TC txns - TC_STATUS = "TC:STATUS", // only track status - TC_TRANSFER = "TC:TRANSFER", // only track status - TC_DEPOSIT = "TC:DEPOSIT", - TC_SEND = "TC:SEND", - TC_SWITCH = "TC:SWITCH", - TC_LP_ADD = "TC:ADDLIQUIDITY", - TC_LP_WITHDRAW = "TC:WITHDRAW", // Supports 'WITHDRAWLIQUIDITY' as well - TC_TNS_CREATE = "TC:TNS-CREATE", - TC_TNS_EXTEND = "TC:TNS-EXTEND", - TC_TNS_UPDATE = "TC:TNS-UPDATE", - // SAVINGS - TC_SAVINGS_ADD = "TC:ADDSAVINGS", - TC_SAVINGS_WITHDRAW = "TC:WITHDRAWSAVINGS", - // LENDING - TC_LENDING_OPEN = "TC:LENDINGOPEN", - TC_LENDING_CLOSE = "TC:LENDINGCLOSE", - // ERC-20 txns - ETH_APPROVAL = "ETH:APPROVAL", - ETH_STATUS = "ETH:STATUS", // only track status - ETH_TRANSFER_TO_TC = "ETH:TRANSFER:IN", - ETH_TRANSFER_FROM_TC = "ETH:TRANSFER:OUT", - // AVAX - AVAX_APPROVAL = "AVAX:APPROVAL", - AVAX_STATUS = "AVAX:STATUS", // only track status - AVAX_TRANSFER_TO_TC = "AVAX:TRANSFER:IN", - AVAX_TRANSFER_FROM_TC = "AVAX:TRANSFER:OUT", - // BSC - BSC_APPROVAL = "BSC:APPROVAL", - BSC_STATUS = "BSC:STATUS", // only track status - BSC_TRANSFER_TO_TC = "BSC:TRANSFER:IN", - BSC_TRANSFER_FROM_TC = "BSC:TRANSFER:OUT", - // Generic types - APPROVAL = "APPROVAL", - STATUS = "STATUS", - TRANSFER_TO_TC = "TRANSFER:IN", - TRANSFER_FROM_TC = "TRANSFER:OUT", - // Unsupported - UNSUPPORTED = "UNSUPPORTED", - // Lending - TC_LENDING = "TC:LENDING", -} - -export enum TxStatus { - PENDING = "pending", - SUCCESS = "success", - CANCELLED = "cancelled", - REFUNDED = "refunded", - REPLACED = "replaced", - ERROR = "error", - UNKNOWN = "unknown", - NOT_STARTED = "not_started", - NOT_FOUND = "not_found", - RETRIES_EXCEEDED = "retries_exceeded", - STREAMING = "streaming", -} - -export enum StreamingSwapProgressStatus { - NOT_STARTED = 0, - SUCCESS = 1, - REFUNDED = 2, -} - -type Calldata = { - amount: string; - amountIn: string; - amountOut: string; - amountOutMin: string; - assetAddress?: string; - data?: string; - deadline?: string; - expiration: number; - fromAsset?: string; - memo: string; - memoStreamingSwap?: string; - router?: string; - tcMemo?: string; - tcRouter?: string; - tcVault?: string; - token?: string; - userAddress: string; - vault?: string; -}; - -type Meta = { - buyChain: Chain; - buyChainGasRate: number; - hasStreamingSwap: boolean; - lastLegEffectiveSlipPercentage: number; - slippagePercentage: number; - priceProtectionDetected: boolean; - priceProtectionRequired: boolean; - providerBuyAssetAmount: { buyAmount: number; chain: string; symbol: string; ticker: string }; - quoteMode: QuoteMode; - sellChain: Chain; - sellChainGasRate: number; - warnings: { warningCode: LedgerErrorCode; warningMessage: string }[]; - thornodeMeta?: { - dustThreshold?: number; - expectedAmountOut: number; - expectedAmountOutStreaming: number; - fees: { affiliate: number; asset: string; outbound: number }; - inboundConfirmationBlocks?: number; - inboundConfirmationSeconds?: number; - maxStreamingSwaps: number; - notes: string; - outboundDelayBlocks: number; - outboundDelaySeconds: number; - streamingSwapBlocks: number; - totalSwapSeconds: number; - warning: string; - }; -}; - -export enum ERROR_CODE { - INVALID_INPUT_PARAMETERS = "1000", - UNKNOWN_PROVIDERS = "1001", - CANNOT_FIND_INBOUND_ADDRESS = "1002", - NO_INBOUND_ADDRESSES = "1003", - CHAIN_HALTED_OR_UNSUPPORTED = "1004", - MISSING_INPUT_PARAMETER = "1005", - INVALID_TYPE_GENERIC = "1100", - INVALID_NUMBER_STRING = "1101", - INVALID_NUMBER = "1102", - INVALID_BOOLEAN = "1103", - INVALID_OBJECT = "1104", - INVALID_ARRAY = "1105", - SELL_AMOUNT_MUST_BE_POSITIVE_INTEGER = "2000", - SELL_BUY_ASSETS_ARE_THE_SAME = "2001", - MISSING_SOURCE_ADDRESS_FOR_SYNTH = "2002", - AFF_ADDRESS_AND_BPS_OR_NEITHER = "2003", - AFF_ADDRESS_TOO_LONG = "2004", - AFF_BPS_INTEGER_MAX_500 = "2005", - SOURCE_ADDRESS_INVALID_FOR_SELL_CHAIN = "2006", - DESTINATION_ADDRESS_INVALID_FOR_BUY_CHAIN = "2007", - PREFERRED_PROVIDER_NOT_SUPPORTED = "2008", - DESTINATION_ADDRESS_SMART_CONTRACT = "2009", - BUY_AMOUNT_MUST_BE_POSITIVE_INTEGER = "2010", - SOURCE_ADDRESS_SMART_CONTRACT = "2011", - SWAP_AMOUNT_TOO_LOW = "2012", - INVALID_PROVIDER = "2100", - MISSING_CROSS_CHAIN_PROVIDER = "2101", - MISSING_AVAX_PROVIDER = "2102", - MISSING_BSC_PROVIDER = "2103", - MISSING_ETH_PROVIDER = "2104", - INVALID_PROVIDER_FOR_SWAP_OUT = "2105", - MISSING_ARB_PROVIDER = "2106", - INVALID_CHAIN = "2200", - INVALID_ASSET = "2201", - INVALID_ASSET_IDENTIFIER = "2202", - UNSUPPORTED_CHAIN = "2204", - UNSUPPORTED_ASSET = "2203", - UNSUPPORTED_ASSET_FOR_SWAPOUT = "2205", - INVALID_SOURCE_ADDRESS = "2300", - INVALID_DESTINATION_ADDRESS = "2301", - THORNODE_QUOTE_GENERIC_ERROR = "3000", - NOT_ENOUGH_SYNTH_BALANCE = "3001", - SYNTH_MINTING_CAP_REACHED = "3002", - INVALID_QUOTE_MODE = "4000", - NO_QUOTES = "4001", - SERVICE_UNAVAILABLE_GENERIC = "5000", - MISSING_GAS_DATA_GENERIC = "5100", - MISSING_TOKEN_INFO_GENERIC = "5200", - CANT_FIND_TOKEN_LIST = "5201", - NO_PRICE = "5202", - PRICE_IS_STALE = "5203", - ADDRESS_NOT_WHITELISTED = "6000", - ADDRESS_ALREADY_CLAIMED = "6001", - TEMPORARY_ERROR = "9999", -} - -export enum ERROR_MODULE { - HEALTH_CONTROLLER = "1000", - LIQUIDITY_CONTROLLER = "1001", - PROVIDER_CONTROLLER = "1002", - QUOTE_CONTROLLER = "1003", - SWAP_CONTROLLER = "1004", - UTIL_CONTROLLER = "1005", - AIRDROP_CONTROLLER = "1006", - PROVIDER = "2000", - ASSET = "2001", - TOKEN_LIST = "2002", - QUOTE = "2100", - QUOTE_TXN_DETAILS = "2101", - THORCHAIN_PROVIDER = "3000", - UNISWAPV2_ETH_PROVIDER = "3001", - UNISWAPV3_ETH_PROVIDER = "3002", - SUSHISWAP_ETH_PROVIDER = "3003", - PANCAKESWAP_BSC_PROVIDER = "3004", - PANCAKESWAP_ETH_PROVIDER = "3005", - ONEINCH_ETH_PROVIDER = "3006", - ONEINCH_BSC_PROVIDER = "3007", - ONEINCH_AVAX_PROVIDER = "3008", - ZEROX_ETH_PROVIDER = "3009", - WOOFI_AVAX_PROVIDER = "3010", - PANGOLIN_AVAX_PROVIDER = "3011", - TRADERJOE_AVAX_PROVIDER = "3012", - KYBER_ETH_PROVIDER = "3013", - KYBER_AVAX_PROVIDER = "3014", - WOOFI_BSC_PROVIDER = "3015", - STARGATE_PROVIDER = "3016", - PROVIDER_UTIL = "4000", - TXN_DETAILS = "5000", - AIRDROP_UTIL = "6000", -} - -export enum ERROR_TYPE { - VALIDATION_ERROR = "VALIDATION_ERROR", - REQUEST_PARAMETER_ERROR = "REQUEST_PARAMETER_ERROR", - RESPONSE_PARSING_ERROR = "RESPONSE_PARSING_ERROR", - UNSUPPORTED = "UNSUPPORTED", - NOT_IMPLEMENTED = "NOT_IMPLEMENTED", - INCOMPATIBLE_ASSETS_OPERATIONS = "INCOMPATIBLE_ASSETS_OPERATIONS", - SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE", - DOWN_FOR_MAINTENANCE = "DOWN_FOR_MAINTENANCE", - MISSING_INBOUND_INFO = "MISSING_INBOUND_INFO", - QUOTE_FETCHING_ERROR = "QUOTE_FETCHING_ERROR", - AIRDROP_ERROR = "AIRDROP_ERROR", - UNHANDLED_ERROR = "UNHANDLED_ERROR", -} - -export const ApiV1ErrorSchema = z.object({ - status: z.number(), - type: z.nativeEnum(ERROR_TYPE), - code: z.nativeEnum(ERROR_CODE), - module: z.nativeEnum(ERROR_MODULE), - complete: z.string(), - identifier: z.string(), - message: z.string(), -}); - -export type ApiV1Error = z.infer; - -export type QuoteResponseV1 = { quoteId: string; routes: QuoteRoute[] } | ApiV1Error; diff --git a/packages/swapkit/core/src/client.ts b/packages/swapkit/core/src/client.ts index b7477fdaa..60d24e187 100644 --- a/packages/swapkit/core/src/client.ts +++ b/packages/swapkit/core/src/client.ts @@ -1,4 +1,11 @@ -import type { EVMTransaction, QuoteResponseRoute } from "@swapkit/api"; +import type { + EVMTransaction, + PriceRequest, + QuoteRequest, + QuoteResponseRoute, + TrackerParams, +} from "@swapkit/api"; +import { SwapKitApi } from "@swapkit/api"; import { ApproveMode, @@ -41,8 +48,6 @@ export type SwapKitParams = { config?: ConnectConfig; plugins?: P; rpcUrls?: { [key in Chain]?: string }; - // TODO: migrate to `config` only - stagenet?: boolean; wallets?: W; }; @@ -54,9 +59,10 @@ export function SwapKit< config = {}, plugins, rpcUrls = {}, - stagenet = false, wallets = {} as Wallets, }: SwapKitParams = {}) { + const stagenet = config.stagenet; + const isDev = config.swapkitConfig?.isDev; type PluginName = keyof Plugins; const connectedWallets = {} as FullWallet; @@ -402,6 +408,26 @@ export function SwapKit< } } + const swapkitConfig = config.swapkitConfig || {}; + const swapkitApiKey = swapkitConfig?.swapkitApiKey || config?.swapkitApiKey; + const referer = swapkitConfig.useHashedApiKey ? swapkitConfig.referer : undefined; + + const api = swapkitApiKey + ? { + getGasRate: () => SwapKitApi.getGasRate(isDev, swapkitApiKey, referer), + getPrice: (body: PriceRequest) => SwapKitApi.getPrice(body, isDev, swapkitApiKey, referer), + getSwapQuote: (params: QuoteRequest) => + SwapKitApi.getSwapQuote(params, isDev, swapkitApiKey, referer), + getTokenList: (provider: string) => SwapKitApi.getTokenList(provider), + getTokenListProviders: () => + SwapKitApi.getTokenListProvidersV2(isDev, swapkitApiKey, referer), + getTokenTradingPairs: (providers: PluginNameEnum[]) => + SwapKitApi.getTokenTradingPairs(providers, isDev, swapkitApiKey, referer), + getTrackerDetails: (payload: TrackerParams) => + SwapKitApi.getTrackerDetails(payload, swapkitApiKey, referer), + } + : { undefined }; + return { ...availablePlugins, ...connectWalletMethods, @@ -424,5 +450,6 @@ export function SwapKit< transfer, validateAddress, verifyMessage, + api, }; } diff --git a/packages/swapkit/helpers/src/modules/swapKitError.ts b/packages/swapkit/helpers/src/modules/swapKitError.ts index 77fd88fca..e45cb767f 100644 --- a/packages/swapkit/helpers/src/modules/swapKitError.ts +++ b/packages/swapkit/helpers/src/modules/swapKitError.ts @@ -120,6 +120,7 @@ const errorCodes = { */ api_v2_invalid_response: 50001, api_v2_server_error: 50002, + api_v2_invalid_method_key_hash: 50003, /** * Toolboxes */ diff --git a/packages/swapkit/helpers/src/types/commonTypes.ts b/packages/swapkit/helpers/src/types/commonTypes.ts index 128256b13..69f014922 100644 --- a/packages/swapkit/helpers/src/types/commonTypes.ts +++ b/packages/swapkit/helpers/src/types/commonTypes.ts @@ -3,12 +3,21 @@ import type { Chain } from "./chains"; import type { ChainApis } from "./sdk"; import type { ChainWallet } from "./wallet"; -export type ConnectConfig = { - stagenet?: boolean; - /** - * @required for swapkit API access - */ +/** + * @optional for swapkit API access + */ +type SwapkitConfig = { + swapkitConfig?: { + isDev?: boolean; + swapkitApiKey?: string; + useHashedApiKey?: boolean; + referer?: string; + }; swapkitApiKey?: string; +}; + +export type ConnectConfig = SwapkitConfig & { + stagenet?: boolean; /** * @required for AVAX & BSC */ diff --git a/packages/toolboxes/cosmos/src/toolbox/BaseCosmosToolbox.ts b/packages/toolboxes/cosmos/src/toolbox/BaseCosmosToolbox.ts index 202a39507..8ed88a051 100644 --- a/packages/toolboxes/cosmos/src/toolbox/BaseCosmosToolbox.ts +++ b/packages/toolboxes/cosmos/src/toolbox/BaseCosmosToolbox.ts @@ -16,9 +16,11 @@ type Params = { export const getFeeRateFromThorswap = async (chainId: ChainId, safeDefault: number) => { try { - const response = await SwapKitApi.getGasRates(); + const response = await SwapKitApi.getGasRate(); - return response.find((gas) => gas.chainId === chainId)?.gas || safeDefault; + const responseGasRate = response.find((gas) => gas.chainId === chainId)?.value; + + return responseGasRate ? Number.parseFloat(responseGasRate) : safeDefault; } catch (e) { console.error(e); return safeDefault; diff --git a/playgrounds/vite/src/swapKitClient.ts b/playgrounds/vite/src/swapKitClient.ts index b5ab28289..d554d29a9 100644 --- a/playgrounds/vite/src/swapKitClient.ts +++ b/playgrounds/vite/src/swapKitClient.ts @@ -24,7 +24,6 @@ export const getSwapKitClient = ( oldKey = key; client = createSwapKit({ - stagenet: params.stagenet, config: { ...params, keepkeyConfig: { From 87952e1090922eb2ea77729a096af9146c22e8a4 Mon Sep 17 00:00:00 2001 From: towan <95243956+towanTG@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:54:44 +0400 Subject: [PATCH 02/26] chore: updates ledger thorchain app (#1105) Co-authored-by: github-actions[bot] --- .changeset/eleven-pans-bathe.md | 5 + .../ledger/src/clients/thorchain/common.ts | 25 +- .../ledger/src/clients/thorchain/helpers.ts | 106 ++++++-- .../ledger/src/clients/thorchain/lib.ts | 228 +++++++++--------- 4 files changed, 220 insertions(+), 144 deletions(-) create mode 100644 .changeset/eleven-pans-bathe.md diff --git a/.changeset/eleven-pans-bathe.md b/.changeset/eleven-pans-bathe.md new file mode 100644 index 000000000..588ead908 --- /dev/null +++ b/.changeset/eleven-pans-bathe.md @@ -0,0 +1,5 @@ +--- +"@swapkit/wallet-ledger": minor +--- + +Updates thorchain ledger app code diff --git a/packages/wallets/ledger/src/clients/thorchain/common.ts b/packages/wallets/ledger/src/clients/thorchain/common.ts index 98bea2633..83f580b38 100644 --- a/packages/wallets/ledger/src/clients/thorchain/common.ts +++ b/packages/wallets/ledger/src/clients/thorchain/common.ts @@ -20,7 +20,15 @@ export const P1_VALUES = { SHOW_ADDRESS_IN_DEVICE: 0x01, }; -const ERROR_DESCRIPTION = { +export const P2_VALUES = { + JSON: 0x0, +}; + +export const ERROR_CODE = { + NoError: 0x9000, +}; + +const ERROR_DESCRIPTION: any = { 1: "U2F: Unknown", 2: "U2F: Bad request", 3: "U2F: Configuration unsupported", @@ -45,19 +53,18 @@ const ERROR_DESCRIPTION = { 28417: "Sign/verify error", }; -export function errorCodeToString(statusCode: any) { - if (statusCode in ERROR_DESCRIPTION) return ERROR_DESCRIPTION[statusCode as 1]; +export function errorCodeToString(statusCode: number) { + if (statusCode in ERROR_DESCRIPTION) return ERROR_DESCRIPTION[statusCode]; return `Unknown Status Code: ${statusCode}`; } +function isDict(v: any) { + return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Date); +} + export function processErrorResponse(response: any) { if (response) { - if ( - typeof response === "object" && - response !== null && - !Array.isArray(response) && - !(response instanceof Date) - ) { + if (isDict(response)) { if (Object.prototype.hasOwnProperty.call(response, "statusCode")) { return { return_code: response.statusCode, diff --git a/packages/wallets/ledger/src/clients/thorchain/helpers.ts b/packages/wallets/ledger/src/clients/thorchain/helpers.ts index 7c808fab5..5ba15c279 100644 --- a/packages/wallets/ledger/src/clients/thorchain/helpers.ts +++ b/packages/wallets/ledger/src/clients/thorchain/helpers.ts @@ -1,23 +1,49 @@ -import { LedgerErrorCode } from "@swapkit/helpers"; +import { + CLA, + ERROR_CODE, + INS, + P2_VALUES, + PAYLOAD_TYPE, + errorCodeToString, + processErrorResponse, +} from "./common"; -import { CLA, INS, PAYLOAD_TYPE, errorCodeToString, processErrorResponse } from "./common"; +export function serializePathv1(path: number[]) { + if (path == null || path.length < 3) { + throw new Error("Invalid path."); + } + if (path.length > 10) { + throw new Error("Invalid path. Length should be <= 10"); + } + const buf = Buffer.alloc(1 + 4 * path.length); + buf.writeUInt8(path.length, 0); + for (let i = 0; i < path.length; i += 1) { + let v = path[i] || 0; + if (i < 3) { + // eslint-disable-next-line no-bitwise + v |= 0x80000000; // Harden + } + buf.writeInt32LE(v, 1 + i * 4); + } + return buf; +} -const signSendChunkv1 = async (app: any, chunkIdx: any, chunkNum: any, chunk: any) => { +export async function signSendChunkv1( + app: any, + chunkIdx: number, + _chunkNum: number, + chunk: Buffer, + txType = P2_VALUES.JSON, +) { return app.transport - .send(CLA, INS.SIGN_SECP256K1, chunkIdx, chunkNum, chunk, [ - LedgerErrorCode.NoError, - 0x6984, - 0x6a80, - ]) + .send(CLA, INS.SIGN_SECP256K1, chunkIdx, txType, chunk, [ERROR_CODE.NoError, 0x6984, 0x6a80]) .then((response: any) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; let errorMessage = errorCodeToString(returnCode); if (returnCode === 0x6a80 || returnCode === 0x6984) { - errorMessage = `${errorMessage} : ${response - .slice(0, response.length - 2) - .toString("ascii")}`; + errorMessage = `${errorMessage} : ${response.slice(0, response.length - 2).toString("ascii")}`; } let signature = null; @@ -31,24 +57,64 @@ const signSendChunkv1 = async (app: any, chunkIdx: any, chunkNum: any, chunk: an error_message: errorMessage, }; }, processErrorResponse); -}; +} + +function compressPublicKey(publicKey: Buffer) { + if (publicKey.length !== 65) { + throw new Error("decompressed public key length should be 65 bytes"); + } + const y = publicKey.subarray(33, 65); + + // @ts-ignore + const z = Buffer.from([2 + (y[y.length - 1] & 1)]); + // @ts-ignore + return Buffer.concat([z, publicKey.subarray(1, 33)]); +} + +export async function publicKeyv1(app: any, data: Buffer) { + return app.transport + .send(CLA, INS.INS_PUBLIC_KEY_SECP256K1, 0, 0, data, [ERROR_CODE.NoError]) + .then((response: any) => { + const errorCodeData = response.slice(-2); + const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; + const pk = Buffer.from(response.slice(0, 65)); + + return { + pk, + compressed_pk: compressPublicKey(pk), + return_code: returnCode, + error_message: errorCodeToString(returnCode), + }; + }, processErrorResponse); +} -export const serializePathv2 = (path: any) => { +export function serializePathv2(path: number[]) { if (!path || path.length !== 5) { throw new Error("Invalid path."); } const buf = Buffer.alloc(20); + // @ts-ignore buf.writeUInt32LE(0x80000000 + path[0], 0); + // @ts-ignore buf.writeUInt32LE(0x80000000 + path[1], 4); + // @ts-ignore buf.writeUInt32LE(0x80000000 + path[2], 8); + // @ts-ignore buf.writeUInt32LE(path[3], 12); + // @ts-ignore buf.writeUInt32LE(path[4], 16); return buf; -}; +} -export const signSendChunkv2 = (app: any, chunkIdx: any, chunkNum: any, chunk: any) => { +export function signSendChunkv2( + app: any, + chunkIdx: number, + chunkNum: number, + chunk: Buffer, + txType = P2_VALUES.JSON, +) { let payloadType = PAYLOAD_TYPE.ADD; if (chunkIdx === 1) { payloadType = PAYLOAD_TYPE.INIT; @@ -57,12 +123,12 @@ export const signSendChunkv2 = (app: any, chunkIdx: any, chunkNum: any, chunk: a payloadType = PAYLOAD_TYPE.LAST; } - return signSendChunkv1(app, payloadType, 0, chunk); -}; + return signSendChunkv1(app, payloadType, 0, chunk, txType); +} -export const publicKeyv2 = async (app: any, data: any) => { +export async function publicKeyv2(app: any, data: Buffer) { return app.transport - .send(CLA, INS.GET_ADDR_SECP256K1, 0, 0, data, [LedgerErrorCode.NoError]) + .send(CLA, INS.GET_ADDR_SECP256K1, 0, 0, data, [ERROR_CODE.NoError]) .then((response: any) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; @@ -75,4 +141,4 @@ export const publicKeyv2 = async (app: any, data: any) => { error_message: errorCodeToString(returnCode), }; }, processErrorResponse); -}; +} diff --git a/packages/wallets/ledger/src/clients/thorchain/lib.ts b/packages/wallets/ledger/src/clients/thorchain/lib.ts index 5dcfa9172..9bfacd205 100644 --- a/packages/wallets/ledger/src/clients/thorchain/lib.ts +++ b/packages/wallets/ledger/src/clients/thorchain/lib.ts @@ -1,4 +1,5 @@ import crypto from "crypto"; +import type Transport from "@ledgerhq/hw-transport"; /** ****************************************************************************** * (c) 2019 ZondaX GmbH * (c) 2016-2017 Ledger @@ -16,39 +17,41 @@ import crypto from "crypto"; * limitations under the License. ******************************************************************************* */ import { bech32 } from "@scure/base"; -import { LedgerErrorCode } from "@swapkit/helpers"; import Ripemd160 from "ripemd160"; import { - APP_KEY, CHUNK_SIZE, CLA, + ERROR_CODE, INS, P1_VALUES, + P2_VALUES, errorCodeToString, getVersion, processErrorResponse, } from "./common"; -import { publicKeyv2, serializePathv2, signSendChunkv2 } from "./helpers"; +import { + publicKeyv1, + publicKeyv2, + serializePathv1, + serializePathv2, + signSendChunkv1, + signSendChunkv2, +} from "./helpers"; export class THORChainApp { - transport: any; + transport: Transport; versionResponse: any; - constructor(transport: any, scrambleKey = APP_KEY) { + constructor(transport: any) { if (!transport) { throw new Error("Transport has not been defined"); } this.transport = transport; - transport.decorateAppAPIMethods( - this, - ["getVersion", "sign", "getAddressAndPubKey", "appInfo", "deviceInfo", "getBech32FromPK"], - scrambleKey, - ); } - static serializeHRP(hrp: any) { + static serializeHRP(hrp: string) { if (hrp == null || hrp.length < 3 || hrp.length > 83) { throw new Error("Invalid HRP"); } @@ -58,52 +61,51 @@ export class THORChainApp { return buf; } - static getBech32FromPK(hrp: any, pk: any) { + static getBech32FromPK(hrp: string, pk: Buffer) { if (pk.length !== 33) { throw new Error("expected compressed public key [31 bytes]"); } - + // @ts-ignore const hashSha256 = crypto.createHash("sha256").update(pk).digest(); + // @ts-ignore const hashRip = new Ripemd160().update(hashSha256).digest(); // @ts-ignore const encode = bech32.encode || bech32.bech32.encode; // @ts-ignore const toWords = bech32.toWords || bech32.bech32.toWords; - + // @ts-ignore return encode(hrp, toWords(hashRip)); } - async serializePath(path: string) { + async serializePath(path: number[]) { this.versionResponse = await getVersion(this.transport); - if (this.versionResponse.return_code !== LedgerErrorCode.NoError) { + if (this.versionResponse.return_code !== ERROR_CODE.NoError) { throw this.versionResponse; } switch (this.versionResponse.major) { + case 1: + return serializePathv1(path); case 2: return serializePathv2(path); default: - return { - return_code: 0x6400, - error_message: "App Version is not supported", - }; + return Buffer.alloc(0); } } - async signGetChunks(path: string, message: any) { + async signGetChunks(path: number[], buffer: Buffer) { const serializedPath = await this.serializePath(path); const chunks = []; chunks.push(serializedPath); - const buffer = Buffer.from(message); for (let i = 0; i < buffer.length; i += CHUNK_SIZE) { let end = i + CHUNK_SIZE; if (i > buffer.length) { end = buffer.length; } - chunks.push(buffer.slice(i, end)); + chunks.push(buffer.subarray(i, end)); } return chunks; @@ -123,46 +125,41 @@ export class THORChainApp { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; - const result = {} as any; - - let appName = "err"; - let appVersion = "err"; + let appName = ""; + let appVersion = ""; let flagLen = 0; let flagsValue = 0; if (response[0] !== 1) { // Ledger responds with format ID 1. There is no spec for any format != 1 - result.error_message = "response format ID not recognized"; - result.return_code = 0x9001; - } else { - const appNameLen = response[1]; - appName = response.slice(2, 2 + appNameLen).toString("ascii"); - let idx = 2 + appNameLen; - const appVersionLen = response[idx]; - idx += 1; - appVersion = response.slice(idx, idx + appVersionLen).toString("ascii"); - idx += appVersionLen; - const appFlagsLen = response[idx]; - idx += 1; - flagLen = appFlagsLen; - flagsValue = response[idx]; + return { + return_code: 0x9001, + error_message: "response format ID not recognized", + }; } + const appNameLen = response[1]; + appName = response.slice(2, 2 + appNameLen).toString("ascii"); + let idx = 2 + appNameLen; + const appVersionLen = response[idx]; + idx += 1; + appVersion = response.slice(idx, idx + appVersionLen).toString("ascii"); + idx += appVersionLen; + const appFlagsLen = response[idx]; + idx += 1; + flagLen = appFlagsLen; + flagsValue = response[idx]; + return { return_code: returnCode, error_message: errorCodeToString(returnCode), - // // appName, appVersion, flagLen, flagsValue, - flag_recovery: (flagsValue & 1) !== 0, - flag_signed_mcu_code: (flagsValue & 2) !== 0, - flag_onboarded: (flagsValue & 4) !== 0, - flag_pin_validated: (flagsValue & 128) !== 0, }; }, processErrorResponse); @@ -170,7 +167,7 @@ export class THORChainApp { async deviceInfo() { return this.transport - .send(0xe0, 0x01, 0, 0, Buffer.from([]), [LedgerErrorCode.NoError, 0x6e00]) + .send(0xe0, 0x01, 0, 0, Buffer.from([]), [ERROR_CODE.NoError, 0x6e00]) .then((response: any) => { const errorCodeData = response.slice(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; @@ -216,44 +213,71 @@ export class THORChainApp { }, processErrorResponse); } - async publicKey(path: string) { + async publicKey(path: number[]) { try { const serializedPath = await this.serializePath(path); switch (this.versionResponse.major) { + case 1: + return publicKeyv1(this, serializedPath); case 2: { - const data = Buffer.concat([THORChainApp.serializeHRP("thor"), serializedPath as Buffer]); - return await publicKeyv2(this, data); + // @ts-ignore + const data = Buffer.concat([THORChainApp.serializeHRP("thor"), serializedPath]); + return publicKeyv2(this, data); } - default: - return { return_code: 0x6400, error_message: "App Version is not supported" }; + return { + return_code: 0x6400, + error_message: "App Version is not supported", + }; } } catch (e) { return processErrorResponse(e); } } - getAddressAndPubKey(path: string, hrp: any) { - try { - return this.executeCommandOnDevice({ path, hrp, command: "ONLY_RETRIEVE" }); - } catch (e) { - return processErrorResponse(e); - } + async getAddressAndPubKey(path: number[], hrp: string, showInDevice = false) { + return this.serializePath(path) + .then((serializedPath: Buffer) => { + // @ts-ignore + const data = Buffer.concat([THORChainApp.serializeHRP(hrp), serializedPath]); + return this.transport + .send( + CLA, + INS.GET_ADDR_SECP256K1, + showInDevice ? P1_VALUES.SHOW_ADDRESS_IN_DEVICE : P1_VALUES.ONLY_RETRIEVE, + 0, + data, + [ERROR_CODE.NoError], + ) + .then((response: any) => { + const errorCodeData = response.slice(-2); + const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; + + const compressedPk = Buffer.from(response.slice(0, 33)); + const bech32Address = Buffer.from(response.slice(33, -2)).toString(); + + return { + bech32_address: bech32Address, + compressed_pk: compressedPk, + return_code: returnCode, + error_message: errorCodeToString(returnCode), + }; + }, processErrorResponse); + }) + .catch((err) => processErrorResponse(err)); } - showAddressAndPubKey(path: string, hrp: any) { - try { - return this.executeCommandOnDevice({ path, hrp, command: "SHOW_ADDRESS_IN_DEVICE" }); - } catch (e) { - return processErrorResponse(e); - } + showAddressAndPubKey(path: number[], hrp: string) { + return this.getAddressAndPubKey(path, hrp, true); } - async signSendChunk(chunkIdx: number, chunkNum: number, chunk: any) { + signSendChunk(chunkIdx: number, chunkNum: number, chunk: Buffer, txType = P2_VALUES.JSON) { switch (this.versionResponse.major) { + case 1: + return signSendChunkv1(this, chunkIdx, chunkNum, chunk, txType); case 2: - return await signSendChunkv2(this, chunkIdx, chunkNum, chunk); + return signSendChunkv2(this, chunkIdx, chunkNum, chunk, txType); default: return { return_code: 0x6400, @@ -262,58 +286,32 @@ export class THORChainApp { } } - async sign(path: string, message: any) { - return this.signGetChunks(path, message).then((chunks) => { - return this.signSendChunk(1, chunks.length, chunks[0]).then(async (response) => { - let result = { - return_code: response.return_code, - error_message: response.error_message, - signature: null, - }; - - for (let i = 1; i < chunks.length; i += 1) { - result = await this.signSendChunk(1 + i, chunks.length, chunks[i]); - if (result.return_code !== LedgerErrorCode.NoError) { - break; - } - } - - return result; - }, processErrorResponse); - }, processErrorResponse); - } + async sign(path: number[], buffer: Buffer, txType = P2_VALUES.JSON) { + let chunks: Buffer[] = []; + let response: any; + try { + chunks = await this.signGetChunks(path, buffer); + response = await this.signSendChunk(1, chunks.length, chunks[0] as Buffer, txType); + } catch (error) { + processErrorResponse(error); + } + let result = { + return_code: response.return_code, + error_message: response.error_message, + signature: null, + }; - private async executeCommandOnDevice({ - path, - hrp, - command, - }: { - path: string; - hrp: any; - command: keyof typeof P1_VALUES; - }) { - const serializedPath = (await this.serializePath(path)) as Uint8Array; - - const response = await this.transport.send( - CLA, - INS.GET_ADDR_SECP256K1, - P1_VALUES[command], - 0, - Buffer.concat([THORChainApp.serializeHRP(hrp), serializedPath]), - [LedgerErrorCode.NoError], - ); - - const errorCodeData = response.slice(-2); - const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; - - const compressedPk = Buffer.from(response.slice(0, 33)); - const bech32Address = Buffer.from(response.slice(33, -2)).toString(); + for (let i = 1; i < chunks.length; i += 1) { + result = await this.signSendChunk(1 + i, chunks.length, chunks[i] as Buffer, txType); + if (result.return_code !== ERROR_CODE.NoError) { + break; + } + } return { - bech32_address: bech32Address, - compressed_pk: compressedPk, - return_code: returnCode, - error_message: errorCodeToString(returnCode), + return_code: result.return_code, + error_message: result.error_message, + signature: result.signature, }; } } From be501990796bfa16e24e609736bafd341db48886 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:35:05 +0400 Subject: [PATCH 03/26] Version Packages (#1106) Co-authored-by: github-actions[bot] --- .changeset/chilled-beds-check.md | 5 ----- .changeset/eleven-pans-bathe.md | 5 ----- .changeset/lazy-scissors-play.md | 9 -------- .changeset/witty-seahorses-check.md | 5 ----- packages/plugins/chainflip/CHANGELOG.md | 11 ++++++++++ packages/plugins/chainflip/package.json | 2 +- packages/plugins/evm/CHANGELOG.md | 9 ++++++++ packages/plugins/evm/package.json | 2 +- packages/plugins/radix/CHANGELOG.md | 8 +++++++ packages/plugins/radix/package.json | 2 +- packages/plugins/thorchain/CHANGELOG.md | 16 ++++++++++++++ packages/plugins/thorchain/package.json | 2 +- packages/swapkit/api/CHANGELOG.md | 15 +++++++++++++ packages/swapkit/api/package.json | 2 +- packages/swapkit/core/CHANGELOG.md | 19 +++++++++++++++++ packages/swapkit/core/package.json | 2 +- packages/swapkit/helpers/CHANGELOG.md | 10 +++++++++ packages/swapkit/helpers/package.json | 2 +- packages/swapkit/sdk/CHANGELOG.md | 13 ++++++++++++ packages/swapkit/sdk/package.json | 2 +- packages/swapkit/wallets/CHANGELOG.md | 22 ++++++++++++++++++++ packages/swapkit/wallets/package.json | 2 +- packages/toolboxes/cosmos/CHANGELOG.md | 12 +++++++++++ packages/toolboxes/cosmos/package.json | 2 +- packages/toolboxes/evm/CHANGELOG.md | 7 +++++++ packages/toolboxes/evm/package.json | 2 +- packages/toolboxes/radix/CHANGELOG.md | 7 +++++++ packages/toolboxes/radix/package.json | 2 +- packages/toolboxes/solana/CHANGELOG.md | 7 +++++++ packages/toolboxes/solana/package.json | 2 +- packages/toolboxes/substrate/CHANGELOG.md | 7 +++++++ packages/toolboxes/substrate/package.json | 2 +- packages/toolboxes/utxo/CHANGELOG.md | 7 +++++++ packages/toolboxes/utxo/package.json | 2 +- packages/wallets/coinbase/CHANGELOG.md | 8 +++++++ packages/wallets/coinbase/package.json | 2 +- packages/wallets/evm-extensions/CHANGELOG.md | 8 +++++++ packages/wallets/evm-extensions/package.json | 2 +- packages/wallets/exodus/CHANGELOG.md | 9 ++++++++ packages/wallets/exodus/package.json | 2 +- packages/wallets/keepkey-bex/CHANGELOG.md | 10 +++++++++ packages/wallets/keepkey-bex/package.json | 2 +- packages/wallets/keepkey/CHANGELOG.md | 10 +++++++++ packages/wallets/keepkey/package.json | 2 +- packages/wallets/keplr/CHANGELOG.md | 8 +++++++ packages/wallets/keplr/package.json | 2 +- packages/wallets/keystore/CHANGELOG.md | 13 ++++++++++++ packages/wallets/keystore/package.json | 2 +- packages/wallets/ledger/CHANGELOG.md | 14 +++++++++++++ packages/wallets/ledger/package.json | 2 +- packages/wallets/okx/CHANGELOG.md | 10 +++++++++ packages/wallets/okx/package.json | 2 +- packages/wallets/phantom/CHANGELOG.md | 10 +++++++++ packages/wallets/phantom/package.json | 2 +- packages/wallets/polkadotjs/CHANGELOG.md | 8 +++++++ packages/wallets/polkadotjs/package.json | 2 +- packages/wallets/radix/CHANGELOG.md | 7 +++++++ packages/wallets/radix/package.json | 2 +- packages/wallets/talisman/CHANGELOG.md | 9 ++++++++ packages/wallets/talisman/package.json | 2 +- packages/wallets/trezor/CHANGELOG.md | 9 ++++++++ packages/wallets/trezor/package.json | 2 +- packages/wallets/wc/CHANGELOG.md | 9 ++++++++ packages/wallets/wc/package.json | 2 +- packages/wallets/xdefi/CHANGELOG.md | 11 ++++++++++ packages/wallets/xdefi/package.json | 2 +- 66 files changed, 354 insertions(+), 55 deletions(-) delete mode 100644 .changeset/chilled-beds-check.md delete mode 100644 .changeset/eleven-pans-bathe.md delete mode 100644 .changeset/lazy-scissors-play.md delete mode 100644 .changeset/witty-seahorses-check.md diff --git a/.changeset/chilled-beds-check.md b/.changeset/chilled-beds-check.md deleted file mode 100644 index 030d4574d..000000000 --- a/.changeset/chilled-beds-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@swapkit/api": minor ---- - -Added x-payload-hash logic and update api v2 requests to include this header diff --git a/.changeset/eleven-pans-bathe.md b/.changeset/eleven-pans-bathe.md deleted file mode 100644 index 588ead908..000000000 --- a/.changeset/eleven-pans-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@swapkit/wallet-ledger": minor ---- - -Updates thorchain ledger app code diff --git a/.changeset/lazy-scissors-play.md b/.changeset/lazy-scissors-play.md deleted file mode 100644 index bdd69dc9f..000000000 --- a/.changeset/lazy-scissors-play.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@swapkit/plugin-thorchain": major -"@swapkit/core": major -"@swapkit/api": major -"@swapkit/toolbox-cosmos": minor -"@swapkit/helpers": minor ---- - -Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. diff --git a/.changeset/witty-seahorses-check.md b/.changeset/witty-seahorses-check.md deleted file mode 100644 index d41ac77ae..000000000 --- a/.changeset/witty-seahorses-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@swapkit/helpers": patch ---- - -Adds new SwapKitError Code diff --git a/packages/plugins/chainflip/CHANGELOG.md b/packages/plugins/chainflip/CHANGELOG.md index 709307bc8..f0554bb5e 100644 --- a/packages/plugins/chainflip/CHANGELOG.md +++ b/packages/plugins/chainflip/CHANGELOG.md @@ -1,5 +1,16 @@ # @swapkit/plugin-chainflip +## 1.4.3 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-substrate@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.4.2 ### Patch Changes diff --git a/packages/plugins/chainflip/package.json b/packages/plugins/chainflip/package.json index 94e9a39ec..f1c02536a 100644 --- a/packages/plugins/chainflip/package.json +++ b/packages/plugins/chainflip/package.json @@ -37,5 +37,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.4.2" + "version": "1.4.3" } diff --git a/packages/plugins/evm/CHANGELOG.md b/packages/plugins/evm/CHANGELOG.md index f1532d768..c1e26329a 100644 --- a/packages/plugins/evm/CHANGELOG.md +++ b/packages/plugins/evm/CHANGELOG.md @@ -1,5 +1,14 @@ # @swapkit/plugin-evm +## 1.3.3 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + ## 1.3.2 ### Patch Changes diff --git a/packages/plugins/evm/package.json b/packages/plugins/evm/package.json index 5f35d53db..fcc5f8016 100644 --- a/packages/plugins/evm/package.json +++ b/packages/plugins/evm/package.json @@ -28,5 +28,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.2" + "version": "1.3.3" } diff --git a/packages/plugins/radix/CHANGELOG.md b/packages/plugins/radix/CHANGELOG.md index 414338f69..0ae56ecfb 100644 --- a/packages/plugins/radix/CHANGELOG.md +++ b/packages/plugins/radix/CHANGELOG.md @@ -1,5 +1,13 @@ # @swapkit/plugin-radix +## 1.2.3 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/helpers@1.18.0 + ## 1.2.2 ### Patch Changes diff --git a/packages/plugins/radix/package.json b/packages/plugins/radix/package.json index 8b422514e..69e689bd0 100644 --- a/packages/plugins/radix/package.json +++ b/packages/plugins/radix/package.json @@ -27,5 +27,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.2" + "version": "1.2.3" } diff --git a/packages/plugins/thorchain/CHANGELOG.md b/packages/plugins/thorchain/CHANGELOG.md index b557ddfea..71a5fa2ec 100644 --- a/packages/plugins/thorchain/CHANGELOG.md +++ b/packages/plugins/thorchain/CHANGELOG.md @@ -1,5 +1,21 @@ # @swapkit/plugin-thorchain +## 2.0.0 + +### Major Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-substrate@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.1.57 ### Patch Changes diff --git a/packages/plugins/thorchain/package.json b/packages/plugins/thorchain/package.json index 99cc5c016..5215fc4cb 100644 --- a/packages/plugins/thorchain/package.json +++ b/packages/plugins/thorchain/package.json @@ -31,5 +31,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.57" + "version": "2.0.0" } diff --git a/packages/swapkit/api/CHANGELOG.md b/packages/swapkit/api/CHANGELOG.md index fce91b850..6ad23b1b5 100644 --- a/packages/swapkit/api/CHANGELOG.md +++ b/packages/swapkit/api/CHANGELOG.md @@ -1,5 +1,20 @@ # @swapkit/api +## 2.0.0 + +### Major Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. + +### Minor Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Added x-payload-hash logic and update api v2 requests to include this header + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.11.2 ### Patch Changes diff --git a/packages/swapkit/api/package.json b/packages/swapkit/api/package.json index 2f548ddac..7dd842a3c 100644 --- a/packages/swapkit/api/package.json +++ b/packages/swapkit/api/package.json @@ -27,5 +27,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.11.2" + "version": "2.0.0" } diff --git a/packages/swapkit/core/CHANGELOG.md b/packages/swapkit/core/CHANGELOG.md index 80fec176a..06f86b2a3 100644 --- a/packages/swapkit/core/CHANGELOG.md +++ b/packages/swapkit/core/CHANGELOG.md @@ -1,5 +1,24 @@ # @swapkit/core +## 3.0.0 + +### Major Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/plugin-evm@1.3.3 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-radix@1.2.22 + - @swapkit/toolbox-solana@1.3.6 + - @swapkit/toolbox-substrate@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 2.1.2 ### Patch Changes diff --git a/packages/swapkit/core/package.json b/packages/swapkit/core/package.json index 7cc22c5e0..32e4dd4f0 100644 --- a/packages/swapkit/core/package.json +++ b/packages/swapkit/core/package.json @@ -34,5 +34,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "2.1.2" + "version": "3.0.0" } diff --git a/packages/swapkit/helpers/CHANGELOG.md b/packages/swapkit/helpers/CHANGELOG.md index 64ad3cdeb..392e96255 100644 --- a/packages/swapkit/helpers/CHANGELOG.md +++ b/packages/swapkit/helpers/CHANGELOG.md @@ -1,5 +1,15 @@ # @swapkit/helpers +## 1.18.0 + +### Minor Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. + +### Patch Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Adds new SwapKitError Code + ## 1.17.2 ### Patch Changes diff --git a/packages/swapkit/helpers/package.json b/packages/swapkit/helpers/package.json index c6b4290e3..23f392390 100644 --- a/packages/swapkit/helpers/package.json +++ b/packages/swapkit/helpers/package.json @@ -35,5 +35,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.17.2" + "version": "1.18.0" } diff --git a/packages/swapkit/sdk/CHANGELOG.md b/packages/swapkit/sdk/CHANGELOG.md index 351c40760..85c70b4ba 100644 --- a/packages/swapkit/sdk/CHANGELOG.md +++ b/packages/swapkit/sdk/CHANGELOG.md @@ -1,5 +1,18 @@ # @swapkit/sdk +## 2.0.12 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/plugin-thorchain@2.0.0 + - @swapkit/core@3.0.0 + - @swapkit/plugin-chainflip@1.4.3 + - @swapkit/plugin-evm@1.3.3 + - @swapkit/plugin-radix@1.2.3 + - @swapkit/wallets@1.2.37 + ## 2.0.11 ### Patch Changes diff --git a/packages/swapkit/sdk/package.json b/packages/swapkit/sdk/package.json index 034eb39f4..299955105 100644 --- a/packages/swapkit/sdk/package.json +++ b/packages/swapkit/sdk/package.json @@ -31,5 +31,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "2.0.11" + "version": "2.0.12" } diff --git a/packages/swapkit/wallets/CHANGELOG.md b/packages/swapkit/wallets/CHANGELOG.md index da0e13815..696f295ed 100644 --- a/packages/swapkit/wallets/CHANGELOG.md +++ b/packages/swapkit/wallets/CHANGELOG.md @@ -1,5 +1,27 @@ # @swapkit/wallets +## 1.2.37 + +### Patch Changes + +- Updated dependencies [[`87952e1`](https://github.com/thorswap/SwapKit/commit/87952e1090922eb2ea77729a096af9146c22e8a4)]: + - @swapkit/wallet-ledger@1.6.0 + - @swapkit/wallet-keepkey@1.4.6 + - @swapkit/wallet-keepkey-bex@1.1.6 + - @swapkit/wallet-keplr@1.1.16 + - @swapkit/wallet-keystore@1.3.6 + - @swapkit/wallet-okx@1.3.6 + - @swapkit/wallet-wc@1.5.6 + - @swapkit/wallet-xdefi@1.3.6 + - @swapkit/wallet-coinbase@1.1.31 + - @swapkit/wallet-evm-extensions@1.1.26 + - @swapkit/wallet-exodus@1.2.32 + - @swapkit/wallet-phantom@1.1.30 + - @swapkit/wallet-polkadotjs@1.0.48 + - @swapkit/wallet-radix@1.2.22 + - @swapkit/wallet-talisman@1.3.13 + - @swapkit/wallet-trezor@1.2.14 + ## 1.2.36 ### Patch Changes diff --git a/packages/swapkit/wallets/package.json b/packages/swapkit/wallets/package.json index c2f6c6dc0..8c0f0924c 100644 --- a/packages/swapkit/wallets/package.json +++ b/packages/swapkit/wallets/package.json @@ -40,5 +40,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.36" + "version": "1.2.37" } diff --git a/packages/toolboxes/cosmos/CHANGELOG.md b/packages/toolboxes/cosmos/CHANGELOG.md index fc855dd6b..893f81199 100644 --- a/packages/toolboxes/cosmos/CHANGELOG.md +++ b/packages/toolboxes/cosmos/CHANGELOG.md @@ -1,5 +1,17 @@ # @swapkit/toolbox-cosmos +## 1.6.0 + +### Minor Changes + +- [#1101](https://github.com/thorswap/SwapKit/pull/1101) [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e) Thanks [@ochhii1337](https://github.com/ochhii1337)! - Removes support for THORSwap API - improves support for SwapkitAPI. Adds api object to the swapkit client. + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/api@2.0.0 + - @swapkit/helpers@1.18.0 + ## 1.5.5 ### Patch Changes diff --git a/packages/toolboxes/cosmos/package.json b/packages/toolboxes/cosmos/package.json index 4a1352ae2..eb77e1b8a 100644 --- a/packages/toolboxes/cosmos/package.json +++ b/packages/toolboxes/cosmos/package.json @@ -41,5 +41,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.5.5" + "version": "1.6.0" } diff --git a/packages/toolboxes/evm/CHANGELOG.md b/packages/toolboxes/evm/CHANGELOG.md index 385875e66..6e0c3c1fa 100644 --- a/packages/toolboxes/evm/CHANGELOG.md +++ b/packages/toolboxes/evm/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/toolbox-evm +## 1.7.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.7.5 ### Patch Changes diff --git a/packages/toolboxes/evm/package.json b/packages/toolboxes/evm/package.json index 1df35c808..a2468e8e9 100644 --- a/packages/toolboxes/evm/package.json +++ b/packages/toolboxes/evm/package.json @@ -32,5 +32,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.7.5" + "version": "1.7.6" } diff --git a/packages/toolboxes/radix/CHANGELOG.md b/packages/toolboxes/radix/CHANGELOG.md index a048acc28..d8b5c5fcc 100644 --- a/packages/toolboxes/radix/CHANGELOG.md +++ b/packages/toolboxes/radix/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/toolbox-radix +## 1.2.22 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.2.21 ### Patch Changes diff --git a/packages/toolboxes/radix/package.json b/packages/toolboxes/radix/package.json index 023b20f35..0efe322b5 100644 --- a/packages/toolboxes/radix/package.json +++ b/packages/toolboxes/radix/package.json @@ -30,5 +30,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.21" + "version": "1.2.22" } diff --git a/packages/toolboxes/solana/CHANGELOG.md b/packages/toolboxes/solana/CHANGELOG.md index 2f7008b24..8dcc0fd79 100644 --- a/packages/toolboxes/solana/CHANGELOG.md +++ b/packages/toolboxes/solana/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/toolbox-solana +## 1.3.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.3.5 ### Patch Changes diff --git a/packages/toolboxes/solana/package.json b/packages/toolboxes/solana/package.json index 92d04a8c5..6b7b6f7b5 100644 --- a/packages/toolboxes/solana/package.json +++ b/packages/toolboxes/solana/package.json @@ -32,5 +32,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.5" + "version": "1.3.6" } diff --git a/packages/toolboxes/substrate/CHANGELOG.md b/packages/toolboxes/substrate/CHANGELOG.md index 5cb94168c..d4d3e2a23 100644 --- a/packages/toolboxes/substrate/CHANGELOG.md +++ b/packages/toolboxes/substrate/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/toolbox-substrate +## 1.3.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.3.5 ### Patch Changes diff --git a/packages/toolboxes/substrate/package.json b/packages/toolboxes/substrate/package.json index 8531b44c2..fcc507355 100644 --- a/packages/toolboxes/substrate/package.json +++ b/packages/toolboxes/substrate/package.json @@ -34,5 +34,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.5" + "version": "1.3.6" } diff --git a/packages/toolboxes/utxo/CHANGELOG.md b/packages/toolboxes/utxo/CHANGELOG.md index 98844bd42..de8225912 100644 --- a/packages/toolboxes/utxo/CHANGELOG.md +++ b/packages/toolboxes/utxo/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/toolbox-utxo +## 1.2.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.2.5 ### Patch Changes diff --git a/packages/toolboxes/utxo/package.json b/packages/toolboxes/utxo/package.json index ba22509af..a02dfe79e 100644 --- a/packages/toolboxes/utxo/package.json +++ b/packages/toolboxes/utxo/package.json @@ -35,5 +35,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.5" + "version": "1.2.6" } diff --git a/packages/wallets/coinbase/CHANGELOG.md b/packages/wallets/coinbase/CHANGELOG.md index 6028aa4f3..8772b3670 100644 --- a/packages/wallets/coinbase/CHANGELOG.md +++ b/packages/wallets/coinbase/CHANGELOG.md @@ -1,5 +1,13 @@ # @swapkit/wallet-coinbase +## 1.1.31 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + ## 1.1.30 ### Patch Changes diff --git a/packages/wallets/coinbase/package.json b/packages/wallets/coinbase/package.json index eb1cf5f22..01dbebf6a 100644 --- a/packages/wallets/coinbase/package.json +++ b/packages/wallets/coinbase/package.json @@ -27,5 +27,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.30" + "version": "1.1.31" } diff --git a/packages/wallets/evm-extensions/CHANGELOG.md b/packages/wallets/evm-extensions/CHANGELOG.md index 724ea3f2c..29f3324a2 100644 --- a/packages/wallets/evm-extensions/CHANGELOG.md +++ b/packages/wallets/evm-extensions/CHANGELOG.md @@ -1,5 +1,13 @@ # @swapkit/wallet-evm-extensions +## 1.1.26 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + ## 1.1.25 ### Patch Changes diff --git a/packages/wallets/evm-extensions/package.json b/packages/wallets/evm-extensions/package.json index 84ce065b1..3f32607cf 100644 --- a/packages/wallets/evm-extensions/package.json +++ b/packages/wallets/evm-extensions/package.json @@ -26,5 +26,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.25" + "version": "1.1.26" } diff --git a/packages/wallets/exodus/CHANGELOG.md b/packages/wallets/exodus/CHANGELOG.md index e4efd1414..ec56548a6 100644 --- a/packages/wallets/exodus/CHANGELOG.md +++ b/packages/wallets/exodus/CHANGELOG.md @@ -1,5 +1,14 @@ # @swapkit/wallet-exodus +## 1.2.32 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.2.31 ### Patch Changes diff --git a/packages/wallets/exodus/package.json b/packages/wallets/exodus/package.json index 7cfc43def..3ab71c36c 100644 --- a/packages/wallets/exodus/package.json +++ b/packages/wallets/exodus/package.json @@ -31,5 +31,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.31" + "version": "1.2.32" } diff --git a/packages/wallets/keepkey-bex/CHANGELOG.md b/packages/wallets/keepkey-bex/CHANGELOG.md index 05a051135..6829c7990 100644 --- a/packages/wallets/keepkey-bex/CHANGELOG.md +++ b/packages/wallets/keepkey-bex/CHANGELOG.md @@ -1,5 +1,15 @@ # @swapkit/wallet-keepkey-bex +## 1.1.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.1.5 ### Patch Changes diff --git a/packages/wallets/keepkey-bex/package.json b/packages/wallets/keepkey-bex/package.json index 071b627fd..240bd47ed 100644 --- a/packages/wallets/keepkey-bex/package.json +++ b/packages/wallets/keepkey-bex/package.json @@ -29,5 +29,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.5" + "version": "1.1.6" } diff --git a/packages/wallets/keepkey/CHANGELOG.md b/packages/wallets/keepkey/CHANGELOG.md index ccd0b652c..def6f9eb0 100644 --- a/packages/wallets/keepkey/CHANGELOG.md +++ b/packages/wallets/keepkey/CHANGELOG.md @@ -1,5 +1,15 @@ # @swapkit/wallet-keepkey +## 1.4.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.4.5 ### Patch Changes diff --git a/packages/wallets/keepkey/package.json b/packages/wallets/keepkey/package.json index 1a107578e..cba081863 100644 --- a/packages/wallets/keepkey/package.json +++ b/packages/wallets/keepkey/package.json @@ -30,5 +30,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.4.5" + "version": "1.4.6" } diff --git a/packages/wallets/keplr/CHANGELOG.md b/packages/wallets/keplr/CHANGELOG.md index 483c85a6c..5658fa3ec 100644 --- a/packages/wallets/keplr/CHANGELOG.md +++ b/packages/wallets/keplr/CHANGELOG.md @@ -1,5 +1,13 @@ # @swapkit/wallet-keplr +## 1.1.16 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + ## 1.1.15 ### Patch Changes diff --git a/packages/wallets/keplr/package.json b/packages/wallets/keplr/package.json index f189570ac..fbb3f4a24 100644 --- a/packages/wallets/keplr/package.json +++ b/packages/wallets/keplr/package.json @@ -27,5 +27,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.15" + "version": "1.1.16" } diff --git a/packages/wallets/keystore/CHANGELOG.md b/packages/wallets/keystore/CHANGELOG.md index 39a25c748..7871a9a8c 100644 --- a/packages/wallets/keystore/CHANGELOG.md +++ b/packages/wallets/keystore/CHANGELOG.md @@ -1,5 +1,18 @@ # @swapkit/wallet-keystore +## 1.3.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-radix@1.2.22 + - @swapkit/toolbox-solana@1.3.6 + - @swapkit/toolbox-substrate@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/wallets/keystore/package.json b/packages/wallets/keystore/package.json index e9a48a148..62e50244f 100644 --- a/packages/wallets/keystore/package.json +++ b/packages/wallets/keystore/package.json @@ -34,5 +34,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.5" + "version": "1.3.6" } diff --git a/packages/wallets/ledger/CHANGELOG.md b/packages/wallets/ledger/CHANGELOG.md index 825811474..c7eece8cd 100644 --- a/packages/wallets/ledger/CHANGELOG.md +++ b/packages/wallets/ledger/CHANGELOG.md @@ -1,5 +1,19 @@ # @swapkit/wallet-ledger +## 1.6.0 + +### Minor Changes + +- [#1105](https://github.com/thorswap/SwapKit/pull/1105) [`87952e1`](https://github.com/thorswap/SwapKit/commit/87952e1090922eb2ea77729a096af9146c22e8a4) Thanks [@towanTG](https://github.com/towanTG)! - Updates thorchain ledger app code + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.5.5 ### Patch Changes diff --git a/packages/wallets/ledger/package.json b/packages/wallets/ledger/package.json index 24219de1a..ca8b772fd 100644 --- a/packages/wallets/ledger/package.json +++ b/packages/wallets/ledger/package.json @@ -43,5 +43,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.5.5" + "version": "1.6.0" } diff --git a/packages/wallets/okx/CHANGELOG.md b/packages/wallets/okx/CHANGELOG.md index 6fda23527..179206646 100644 --- a/packages/wallets/okx/CHANGELOG.md +++ b/packages/wallets/okx/CHANGELOG.md @@ -1,5 +1,15 @@ # @swapkit/wallet-okx +## 1.3.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/wallets/okx/package.json b/packages/wallets/okx/package.json index ddb040d90..6de60a874 100644 --- a/packages/wallets/okx/package.json +++ b/packages/wallets/okx/package.json @@ -28,5 +28,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.5" + "version": "1.3.6" } diff --git a/packages/wallets/phantom/CHANGELOG.md b/packages/wallets/phantom/CHANGELOG.md index 5f0cf8fe1..16342cdef 100644 --- a/packages/wallets/phantom/CHANGELOG.md +++ b/packages/wallets/phantom/CHANGELOG.md @@ -1,5 +1,15 @@ # @swapkit/wallet-phantom +## 1.1.30 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-solana@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.1.29 ### Patch Changes diff --git a/packages/wallets/phantom/package.json b/packages/wallets/phantom/package.json index 71d131fc4..014accf2a 100644 --- a/packages/wallets/phantom/package.json +++ b/packages/wallets/phantom/package.json @@ -29,5 +29,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.1.29" + "version": "1.1.30" } diff --git a/packages/wallets/polkadotjs/CHANGELOG.md b/packages/wallets/polkadotjs/CHANGELOG.md index b71110ad4..dea0b40db 100644 --- a/packages/wallets/polkadotjs/CHANGELOG.md +++ b/packages/wallets/polkadotjs/CHANGELOG.md @@ -1,5 +1,13 @@ # @swapkit/wallet-polkadotjs +## 1.0.48 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-substrate@1.3.6 + ## 1.0.47 ### Patch Changes diff --git a/packages/wallets/polkadotjs/package.json b/packages/wallets/polkadotjs/package.json index cf7a3d505..ef02ea79d 100644 --- a/packages/wallets/polkadotjs/package.json +++ b/packages/wallets/polkadotjs/package.json @@ -28,5 +28,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.0.47" + "version": "1.0.48" } diff --git a/packages/wallets/radix/CHANGELOG.md b/packages/wallets/radix/CHANGELOG.md index 202395b4e..0c2459e21 100644 --- a/packages/wallets/radix/CHANGELOG.md +++ b/packages/wallets/radix/CHANGELOG.md @@ -1,5 +1,12 @@ # @swapkit/wallet-radix +## 1.2.22 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + ## 1.2.21 ### Patch Changes diff --git a/packages/wallets/radix/package.json b/packages/wallets/radix/package.json index 0f04309f0..09a348714 100644 --- a/packages/wallets/radix/package.json +++ b/packages/wallets/radix/package.json @@ -29,5 +29,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.21" + "version": "1.2.22" } diff --git a/packages/wallets/talisman/CHANGELOG.md b/packages/wallets/talisman/CHANGELOG.md index b4bcfafbb..ad89f8385 100644 --- a/packages/wallets/talisman/CHANGELOG.md +++ b/packages/wallets/talisman/CHANGELOG.md @@ -1,5 +1,14 @@ # @swapkit/wallet-talisman +## 1.3.13 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-substrate@1.3.6 + ## 1.3.12 ### Patch Changes diff --git a/packages/wallets/talisman/package.json b/packages/wallets/talisman/package.json index 24792cc4c..61b4ed1ca 100644 --- a/packages/wallets/talisman/package.json +++ b/packages/wallets/talisman/package.json @@ -29,5 +29,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.12" + "version": "1.3.13" } diff --git a/packages/wallets/trezor/CHANGELOG.md b/packages/wallets/trezor/CHANGELOG.md index ec707df67..144da28a3 100644 --- a/packages/wallets/trezor/CHANGELOG.md +++ b/packages/wallets/trezor/CHANGELOG.md @@ -1,5 +1,14 @@ # @swapkit/wallet-trezor +## 1.2.14 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.2.13 ### Patch Changes diff --git a/packages/wallets/trezor/package.json b/packages/wallets/trezor/package.json index 3b9f59d4a..ac7c9693e 100644 --- a/packages/wallets/trezor/package.json +++ b/packages/wallets/trezor/package.json @@ -28,5 +28,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.2.13" + "version": "1.2.14" } diff --git a/packages/wallets/wc/CHANGELOG.md b/packages/wallets/wc/CHANGELOG.md index c090bc913..aebddf8cf 100644 --- a/packages/wallets/wc/CHANGELOG.md +++ b/packages/wallets/wc/CHANGELOG.md @@ -1,5 +1,14 @@ # @swapkit/wallet-wc +## 1.5.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + ## 1.5.5 ### Patch Changes diff --git a/packages/wallets/wc/package.json b/packages/wallets/wc/package.json index 69b692089..4a27c56b6 100644 --- a/packages/wallets/wc/package.json +++ b/packages/wallets/wc/package.json @@ -37,5 +37,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.5.5" + "version": "1.5.6" } diff --git a/packages/wallets/xdefi/CHANGELOG.md b/packages/wallets/xdefi/CHANGELOG.md index 71873a6e4..143cf0f30 100644 --- a/packages/wallets/xdefi/CHANGELOG.md +++ b/packages/wallets/xdefi/CHANGELOG.md @@ -1,5 +1,16 @@ # @swapkit/wallet-xdefi +## 1.3.6 + +### Patch Changes + +- Updated dependencies [[`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e), [`c634681`](https://github.com/thorswap/SwapKit/commit/c634681d1d36f7be272d285c09a832e61e64767e)]: + - @swapkit/toolbox-cosmos@1.6.0 + - @swapkit/helpers@1.18.0 + - @swapkit/toolbox-evm@1.7.6 + - @swapkit/toolbox-solana@1.3.6 + - @swapkit/toolbox-utxo@1.2.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/wallets/xdefi/package.json b/packages/wallets/xdefi/package.json index 7c88b344f..5274beb8b 100644 --- a/packages/wallets/xdefi/package.json +++ b/packages/wallets/xdefi/package.json @@ -30,5 +30,5 @@ }, "type": "module", "types": "./src/index.ts", - "version": "1.3.5" + "version": "1.3.6" } From d88fe02d8683a74a9b2f521b60381032099e5c40 Mon Sep 17 00:00:00 2001 From: towan <95243956+towanTG@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:54:07 +0400 Subject: [PATCH 04/26] Feat/kado plugin (#1107) * wip: kado plugin * fix: Correct function name and update parameters in offRampQuote * fix: update the on and off ramp quote functions in the Kado plugin The commit message is: fix: update the on and off ramp quote functions in the Kado plugin * fix: update Kado plugin to use new API endpoints * feat: add KadoQuoteResponse type * feat: Update onRampQuote and offRampQuote functions in Kado plugin * feat: Extend KadoQuoteRequest type with additional fiat methods and currencies * feat: add getOrderStatus with GET * feat: adds kado quoting * feat: adds kado tokenlist * feat: WIP kado plugin updates * feat: fix kado quote mapping * feat: kado plugin * chore: fix lint issues * chore: remove aider files --------- Co-authored-by: github-actions[bot] --- .changeset/witty-rats-arrive.md | 12 + bun.lockb | Bin 726846 -> 727366 bytes packages/plugins/kado/CHANGELOG.md | 0 packages/plugins/kado/build.ts | 4 + packages/plugins/kado/package.json | 32 ++ packages/plugins/kado/src/helpers.ts | 29 ++ packages/plugins/kado/src/index.ts | 1 + packages/plugins/kado/src/plugin.ts | 339 ++++++++++++++++++ packages/plugins/kado/src/types.ts | 212 +++++++++++ packages/plugins/kado/tsconfig.json | 4 + packages/plugins/radix/src/index.ts | 2 +- packages/plugins/thorchain/src/tcPlugin.ts | 3 +- packages/swapkit/core/src/client.ts | 19 +- packages/swapkit/helpers/src/helpers/asset.ts | 24 ++ packages/swapkit/helpers/src/types/chains.ts | 10 +- .../swapkit/helpers/src/types/commonTypes.ts | 9 +- .../helpers/src/types/derivationPath.ts | 3 +- packages/swapkit/helpers/src/types/quotes.ts | 1 + packages/swapkit/helpers/src/types/wallet.ts | 8 +- packages/swapkit/sdk/package.json | 1 + packages/swapkit/sdk/src/index.ts | 2 + packages/swapkit/tokens/src/index.ts | 1 + .../swapkit/tokens/src/tokenLists/kado.ts | 276 ++++++++++++++ packages/wallets/ledger/src/ledgerLive.ts | 7 +- playgrounds/nextjs/package.json | 1 + playgrounds/nextjs/src/app/offRamp/page.tsx | 17 + playgrounds/nextjs/src/lib/swapKit.ts | 3 +- playgrounds/vite/src/App.tsx | 14 +- playgrounds/vite/src/Send/index.tsx | 18 +- playgrounds/vite/src/Swap/SwapInputs.tsx | 12 +- playgrounds/vite/src/TNS/index.tsx | 12 +- playgrounds/vite/src/Wallet.tsx | 4 +- playgrounds/vite/src/WalletPicker.tsx | 2 +- playgrounds/vite/vite.config.ts | 3 + 34 files changed, 1039 insertions(+), 46 deletions(-) create mode 100644 .changeset/witty-rats-arrive.md create mode 100644 packages/plugins/kado/CHANGELOG.md create mode 100644 packages/plugins/kado/build.ts create mode 100644 packages/plugins/kado/package.json create mode 100644 packages/plugins/kado/src/helpers.ts create mode 100644 packages/plugins/kado/src/index.ts create mode 100644 packages/plugins/kado/src/plugin.ts create mode 100644 packages/plugins/kado/src/types.ts create mode 100644 packages/plugins/kado/tsconfig.json create mode 100644 packages/swapkit/tokens/src/tokenLists/kado.ts create mode 100644 playgrounds/nextjs/src/app/offRamp/page.tsx diff --git a/.changeset/witty-rats-arrive.md b/.changeset/witty-rats-arrive.md new file mode 100644 index 000000000..53b05168a --- /dev/null +++ b/.changeset/witty-rats-arrive.md @@ -0,0 +1,12 @@ +--- +"@swapkit/plugin-thorchain": minor +"@swapkit/helpers": minor +"@swapkit/tokens": minor +"@swapkit/wallet-ledger": minor +"@swapkit/plugin-radix": minor +"@swapkit/plugin-kado": minor +"@swapkit/core": minor +"@swapkit/sdk": minor +--- + +Adds Kado plugin diff --git a/bun.lockb b/bun.lockb index c81d7094a8f9d3b24f6af6ad5ff973658182f72b..60765b0a1408fd34498b966b8f26e5882f13b7da 100755 GIT binary patch delta 122315 zcmbrH2VhlI*0%4taN!=BN)f~Y*f402Sh$g3t{@gr5fytQK!6J=q##X9>z2V$fl0D|%QZZ=ZMgKnfqprCj&AmR`YI@Ime!B7F1#9nk|NcIm6Z*V< z$&vjI==gYth$Ir5gBvFjjn8yUBszh$|OA?BVUo(4dFs+s`3{OYbRN6qXN(C-7u-ERehV>9+bM1DylV*c2%n$lq%i9 zUSJ3GQ&&Gzs1G=`S_&o-lh8-`kAoV*I8g1CcenPkaQ)R(SAdtr0VcwN~24@ z!i@5{C#m75ds>In$S2vjl8RF3AUO7F+=}|@u$#kgA!_H*O>F@8fU?)D zVb#n^8d-rrnjgt zi=4dw7FO;IP-=A8IJhyneS^Q1(P1>pe~kfL_|2B4^|t*?naw~odm#D3-^drn&9%VQ z>?((EfouC10+@xttL$0oTPC0lH za=F~ZZEf5$%j%~UGFMwrkEw1Pv7IR}6qKSHyY^~xm9=G45{ao5)f1WaM51YXD^QuM z%FQgRtNRu%MFNm1YkUbJ-g^h@umaTdoaf4=3T)ngM6L;lEgD;@evrwZ2GOB$9`)oW z(L`y!J)|1RT6$5&mOBN)t$3YFro1(&q%-SC#noLM%hx}NbrxN{=0HM!M85{b>g z$)HN#h+JCN7bOx*LE{B*brPFzK3wK`YZr5ec+_*tDk^ey^@(A-+Gro8KODI++%3X} z#&1YS{krN&GwQH^{q8nD(?Q99bvV6lVinnmv#es{EQjTwMmIKN4Ic@Y8JDAou)Jzg z_2gXD)EULr-jkr_e_OCy;($b>G@VzGn>gB4d}$9iZ_{z*2?K{x@}xa zdD(Vq*{rGMD1H5YHmFNM^>$v6>)3B}>;mx&O)BGm)5;Ux7@NVhqyOB5pCWH-!bQQ# zj=dY=5v&+t>-#BCx*Wy0SWRCkZxP|ywbKECEjcq9?du2iCejnw!fy6~Dj8Vtg z81{4RErrXT{os^uXdHKlspTVxW-d3iuD-gq{J=x4V*RWsh12n+XC3c)m?^M5oQT|5 z3aZ0RK`B&GJ-Muoh;$F5&_J%?A4Rz7(`QAVfV)O$6FmcK6LBWuneQBK3cL!c;@L-- ztGxt@PpmDQRE{E}jx_mspgMjZRDNZ7?bPyJ5{Z*3uYs_EM8WL&qpW;IaERZ#?7*YV z&Rvf&dmRnRe#cQu>f@eKwe60zR&!IUFh(L#R}qaWaRyzfxA_jICqDvI{Sja<@HP$}G}+L2ItdwJEx}w0+zFDAmtRG`hI=8X{DG6r-6qx5)z6(- zo`~z$lP~l9eTvop8>n{wxczLn?Ub~JmCJAibsPuMCul$&-s><5z=bm_Kg^j$ih|8L z4;&Cj%?pukM(LR|rWP_YiP+k*a<*Y7{9A2JudA+_lB+1cnKq?tedWx^#kQ-qzT?de&#A91JA(3B+>cRS<)%75lOSE6E3b|7GsydqKM>Sx z%`9Y?_2sn|eH-ZfBx|Sx1>_e$(6KDA*K9Z4pcMEQD8FkWU*)FHu?G84Pvzf3uILiF z{71n4@Z&*FD2=CpnujdNNvE;jeCpGGV|Nm=z`y6&zIzn@qJ}238&{!R<;ivm?6bfW zIKkmxKq*pRyW3FBRW~OeLw#A~Xd2%VECqFn+zyliT|q^ib*Cf}gO&JzL~n38s1>u+ zVTp6xdDVC}pUqDTUhKNPcT=#oYww1xr&%w@oM97uFetBXhg@drNoCplvko?|KeaO~ zpER=!FHFqNVK+V(ooQx1^en4iH?3^2V&yGxIsH~=8&*!%G~nFxmMua)p<@# zwy|`f>0MvP0RerxUSMsmLoVaJ3d%i(fU^3;sz}YmMHkw_nghzXuToF5Rp$7|lox*l z#P1s#AH3K)yw2h2pr)+~)WT?T6%Joy9bW_2F#3U72wh!%?Hrjekyv}a4QRVdZB{o1 z)y_|WDKrn10`-?Ezai1M&E-xbuz-xZ%IXSyFflu7E|C~{g^lnshsB_*d^zQ}1MdnA zXT$r!FNOl>kXa=HuNHqa3)=OgPH0v zP!(@={4#t(75tm5fmvV|c2LTpc_QYUHzK<)Wn+2gh}PF-uHj2jzfUx9_dC=vE_F`RQeIiR&yj zH-%%H%p&#EYO7~Wot78@mnF;RHt1N8NbKeW_uXa;W!9u8v{_ z*1P;_Rhn(Z^9}W6GU$rtz((Ft_S>*u6IAtoQ1v zjO+FvXb9%6{$H0R4YGf9ZIw_Y(tbf$TSYKCNt6t~BWy~{z0X=)~aqu!5 z!SuR9V&|@jELZzTZW?Db-6Z%`ou~*;56(nTdc$eWBA^Kbt9NlZ+h})K1wQC&S z{epE@RyDV>tbWq8$EdBL*J3aqeCkDOZAST|No6wuil>yFkgbexqsodZ(8 z(Fc>OHlBaUhEQ99u6(w5*;KzCl({bkqapIJJF`AF>5^A$w><@vBhLzs-n3uCFj|wF zJh{?p-2k^AnyuZ1aATnG+<9}Vsb4g?uy~R=Sn;Xlmx7wuUp}$j`4xwsfl}Zw@^$#y9_$15 z0DEZHefe{%_z(rv(To;r_-^DH$wsSfgb#!2@Op4_@Te~=f|fgfI|sP};ExYl`8bFy zTw@CF`ISvX0VsvG`5N9pViOW-m}iz8t2412t{ETmZ*#?q!EW$n$UA`vaFaIW>(`nm zOaoOfE@!u3C`pGKsXUjF+?gb%erF0@y$<{9e0nMg?HN-Yjs<0^-5qWT%48{rU(tX@ z`Zg$wJp=Xx9|WbqouCw*TNN$T#9=Ofw3AQHO_`#clJ62HL?a_;MJ0<|0q((SRd)bf zKE8=V&*9o{P5uU`0R+FA!kesjdkoH@@((*&{rl6VTSfUvkx}n}%fweY zyeU|@dGE3}UFovAxmA;}U)jWowdE%z64TI49&>`T!1&k_?$+Y_&R(Q@aTn`lU-G+A z{w26##|+&MR8L9l5scoVpT9M^vhLKNW{Z9e|LkUUzT3#GG-YGMn!0F86FY5UJOtI| zd7#?dy}R|f6R44&id;CyVQCL93fuR9a=x8Ft&*wLGbgL%>)|~WK)7V9RKU_+ssk7ivfJwsvxLWwo`O!N$Pl29wI_$}7t2 z>b|5MKe2bBaktH^p~_rkdEw-ViS6L>n;$`qIGT+ax%#)F3ayGg2baGs4OVVBupz!v z_!K*;)@z`K5uaGbZskQ`r>wlruCliDBJaK1;RLV;<*#;pDCK3hI=I@|%JKLlIeBs!S9q48@9YFgiQ4V>*NPO7fpjG0Kp*FN#L2l1`{AHQ9=eQUFC*_>Rpd|=qN zHXyTCqA_-#va0%u+TH5w{*D86(#FIMMou%kCh+?8ZdkRQH8Z)qd}d*JO~spVt*_@m zS@&4Ns-|NcD0wL;{}=>nyzw=~AMaQGwu80XnR41^>dPipl+)`TgKQQXK-x_<4hpX9 z*KfqZJDU0S0@dy31vY7uICx9hs%pE<`1s32Vh8f$Q_3Tb9~k`9FSAL!x9m9Bi#D|@ zgAx6EH@w46Ar+n~G7DWso$cX7kX#iT!G*h6U$a5YOxJd{@V?pARIRA4isI&nyIHwc z96s*w4lr^FP|N>3hs7X)uc5J)gnZ;gPz4VHWy4SD02?$O;F*ozg3D9q)YbECVP#@z zu{C%rs3kOd595CUH5ZeRcLfguwLt{KjA!BU?K9!swD<0cKpo9OpbnZ{M>l~gIDWW| z{3%fUN#qLImxJnHd)HBHk?y6YKx~<_DW_SR4XXX|XWEWco24CfJf4KSWm@ph0sR{G zBwL0a1j-)z&Q$hzW`s3+(nuTcqo8V+gEDL!LUi9xWJr{sR9;n&?_aUEb$i?>D>rkN zUFv-Xm-=I=um0+0@-(wcBAM7TICbmZ4TBJ?`vIUrVsB7p?&kQ+TvfGvFTKAt^Vxo; z&bOefvl5iqp8_@dJ3$TdCQ#FJ3&Yt8oHxdc_WjY!^A_+|4I3KwJkW~{0QV!%!Jr6~ zpKJlDgLPDtf(vL!yz^Mgj}?o@^(}G@VCcc7V64cV3`BN|72I$j_(g2!G#yIwzK5E| z>ksjw4gVuhXRxylb3qQ2LL)(qcp|6{4srO|c=MlKUH*&I*MJr=0JXpFaBIKj2rR7= z#WWJqd=@8keX6IF^Ekul;>ci^ZTBt69c?pGSy3@p*;^cI#V2ux%Yi;IJy#!vvg3jq zw#_z-KF)fdR9jtFNBrFjuEr0d6=}P-Yb{qdbhn8-)_Nz}Xt?~JU00DvT<-V}pz84@ z>7+7xy=sD$y8x6soeIh=TEC%_-|F!E8D_zA;Iib#6^8TRiWgO27oD*?Ra%3; zQa~BsfLc-?fExKE3QB>xDl_3n&cid+Ui4Jb2h_-aCtr$Bm}!yn9#D!-p}g8Tw#M>L zDyyi^;W}QemuS!u|BejJ(I`;7rdHoy@}TY>*y9KIKR(#U5At`_nPOLgT5|CNeEf~{ z%Μ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

1AIrjpTmNAZ?J8O?_XHJ?1+vb_x6 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

upN?mqalzv$!7pj{Ppqky+;Q^rH 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 a$jRQq-lB{4?pIq23aOLVg?_NNNcw*y0^6$q diff --git a/packages/plugins/kado/CHANGELOG.md b/packages/plugins/kado/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/plugins/kado/build.ts b/packages/plugins/kado/build.ts new file mode 100644 index 000000000..e7817001f --- /dev/null +++ b/packages/plugins/kado/build.ts @@ -0,0 +1,4 @@ +import { buildPackage } from "../../../tools/builder"; +import { dependencies } from "./package.json"; + +buildPackage({ dependencies }); diff --git a/packages/plugins/kado/package.json b/packages/plugins/kado/package.json new file mode 100644 index 000000000..7ee55d96d --- /dev/null +++ b/packages/plugins/kado/package.json @@ -0,0 +1,32 @@ +{ + "author": "swapkit-oss", + "dependencies": { + "@swapkit/api": "workspace:*", + "@swapkit/helpers": "workspace:*" + }, + "description": "SwapKit Plugin - Kado", + "files": [ + "src/", + "dist/" + ], + "homepage": "https://github.com/thorswap/SwapKit", + "license": "Apache-2.0", + "main": "./dist/index.js", + "name": "@swapkit/plugin-kado", + "react-native": "./src/index.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/thorswap/SwapKit.git" + }, + "scripts": { + "build": "bun run ./build.ts", + "clean": "rm -rf dist node_modules *.tsbuildinfo", + "lint": "biome check --write ./src", + "test": "echo 'bun test'", + "test:coverage": "bun test --coverage", + "type-check": "tsc --noEmit" + }, + "type": "module", + "types": "./src/index.ts", + "version": "0.0.0" +} diff --git a/packages/plugins/kado/src/helpers.ts b/packages/plugins/kado/src/helpers.ts new file mode 100644 index 000000000..19100ea14 --- /dev/null +++ b/packages/plugins/kado/src/helpers.ts @@ -0,0 +1,29 @@ +import { Chain } from "@swapkit/helpers"; + +export const SupportedKadoChain = { + thorchain: Chain.THORChain, + solana: Chain.Solana, + polygon: Chain.Polygon, + Optimism: Chain.Optimism, + litecoin: Chain.Litecoin, + kujira: Chain.Kujira, + ethereum: Chain.Ethereum, + "cosmos hub": Chain.Cosmos, + bitcoin: Chain.Bitcoin, + base: Chain.Base, + Avalanche: Chain.Avalanche, + Arbitrum: Chain.Arbitrum, +}; + +export const ChainToKadoChain = (chain: Chain) => { + const entries = Object.entries(SupportedKadoChain); + const found = entries.find(([_, value]) => value === chain); + if (!found) throw new Error(`Chain ${chain} not supported`); + return found[0]; +}; + +export const KadoChainToChain = (kadoChain: string) => { + const found = Object.keys(SupportedKadoChain).includes(kadoChain); + if (!found) throw new Error(`KadoChain ${kadoChain} not supported`); + return SupportedKadoChain[kadoChain as keyof typeof SupportedKadoChain]; +}; diff --git a/packages/plugins/kado/src/index.ts b/packages/plugins/kado/src/index.ts new file mode 100644 index 000000000..39b9a61b2 --- /dev/null +++ b/packages/plugins/kado/src/index.ts @@ -0,0 +1 @@ +export * from "./plugin"; diff --git a/packages/plugins/kado/src/plugin.ts b/packages/plugins/kado/src/plugin.ts new file mode 100644 index 000000000..d589e60bc --- /dev/null +++ b/packages/plugins/kado/src/plugin.ts @@ -0,0 +1,339 @@ +import type { QuoteResponse, QuoteResponseRoute } from "@swapkit/api"; +import { + type AssetValue, + Chain, + FeeTypeEnum, + ProviderName, + RequestClient, + blockTimes, +} from "@swapkit/helpers"; +import type { SwapKitPluginParams } from "@swapkit/helpers"; +import { ChainToKadoChain } from "./helpers"; +import type { + KadoFiatCurrency, + KadoFiatMethod, + KadoQuoteRequest, + KadoQuoteResponse, +} from "./types"; + +function mapKadoQuoteToQuoteResponse({ + quote, + sellAsset, + buyAsset, +}: { + quote: KadoQuoteResponse; + sellAsset: AssetValue; + buyAsset: AssetValue; +}): QuoteResponse { + const isOnRamp = sellAsset.chain === Chain.Fiat; + + const buyAssetAmount = buyAsset.set( + isOnRamp + ? quote.data.quote.receive.unitCount.toString() + : quote.data.quote.receive.amount.toString(), + ); + const totalSlippageBps = isOnRamp + ? Math.round((quote.data.quote.totalFee.amount / quote.data.quote.receive.amount) * 10_000) + : Math.round( + (quote.data.quote.totalFee.amount / + (quote.data.quote.price.price * quote.data.quote.baseAmount.amount)) * + 10_000, + ); + + const inboundChain = sellAsset.chain; + const outboundChain = buyAsset.chain; + + const inbound = Math.ceil(blockTimes[inboundChain] * 3); + const swap = Math.ceil(60); + const outbound = Math.ceil(blockTimes[outboundChain]); + const routes: QuoteResponseRoute[] = [ + { + providers: [ProviderName.KADO], + sellAsset: sellAsset.toString(), + sellAmount: sellAsset.getValue("string"), + buyAsset: buyAsset.toString(), + expectedBuyAmount: buyAssetAmount.getValue("string"), + expectedBuyAmountMaxSlippage: buyAssetAmount.getValue("string"), + sourceAddress: "{sourceAddress}", + destinationAddress: "{destinationAddress}", + fees: [ + { + asset: quote.data.quote.processingFee.currency, + amount: quote.data.quote.processingFee.amount.toString(), + type: FeeTypeEnum.LIQUIDITY, + protocol: ProviderName.KADO, + chain: Chain.Fiat, + }, + { + asset: quote.data.quote.networkFee.currency, + amount: quote.data.quote.networkFee.amount.toString(), + type: FeeTypeEnum.NETWORK, + protocol: ProviderName.KADO, + chain: buyAsset.chain, + }, + ], + totalSlippageBps, + legs: [ + { + provider: ProviderName.KADO, + sellAsset: sellAsset.toString(), + sellAmount: sellAsset.getValue("string"), + buyAsset: buyAsset.toString(), + buyAmount: quote.data.quote.receive.unitCount.toString(), + buyAmountMaxSlippage: quote.data.quote.receive.unitCount.toString(), + fees: [ + { + asset: quote.data.quote.processingFee.currency, + amount: quote.data.quote.processingFee.amount.toString(), + type: FeeTypeEnum.LIQUIDITY, + protocol: ProviderName.KADO, + chain: Chain.Fiat, + }, + { + asset: quote.data.quote.networkFee.currency, + amount: quote.data.quote.networkFee.amount.toString(), + type: FeeTypeEnum.NETWORK, + protocol: ProviderName.KADO, + chain: buyAsset.chain, + }, + ], + }, + ], + warnings: [], + meta: { + tags: [], + }, + estimatedTime: { + inbound, + swap, + outbound, + total: inbound + swap + outbound, + }, + }, + ]; + + return { + quoteId: crypto.randomUUID(), + routes, + error: quote.success ? undefined : quote.message, + }; +} + +export type KadoBlockchainsResponse = { + success: boolean; + message: string; + data: { + blockchains: { + _id: string; + supportedEnvironment: string; + network: string; + origin: string; + label: string; + associatedAssets: { + _id: string; + name: string; + description: string; + label: string; + supportedProviders: string[]; + stablecoin: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + }; + avgTransactionTimeSeconds: number; + usesAvaxRouter: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + }[]; + }; +}; + +export type KadoSupportedAssetsResponse = { + success: boolean; + message: string; + data: { + assets: { + _id: string; + name: string; + description: string; + label: string; + symbol: string; + supportedProviders: string[]; + stablecoin: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + }[]; + }; +}; + +function plugin({ config: { kadoApiKey } }: SwapKitPluginParams<{ kadoApiKey: string }>) { + async function fetchProviderQuote({ + sellAsset, + buyAsset, + fiatMethod, + }: { + sellAsset: AssetValue; + buyAsset: AssetValue; + fiatMethod: KadoFiatMethod; + }): Promise { + try { + const isOnRamp = sellAsset.chain === Chain.Fiat; + + const transactionType = isOnRamp ? "buy" : "sell"; + + const currency = (isOnRamp ? sellAsset.symbol : buyAsset.symbol) as KadoFiatCurrency; + + const asset = isOnRamp ? buyAsset : sellAsset; + + const quoteRequest: KadoQuoteRequest = { + transactionType, + fiatMethod, + partner: "fortress", + amount: sellAsset.getValue("string"), + asset: asset.symbol, + blockchain: ChainToKadoChain(asset.chain), + currency, + }; + + const quote = await RequestClient.get( + "https://api.kado.money/v2/ramp/quote", + { + searchParams: quoteRequest, + headers: { + "X-Widget-Id": kadoApiKey, + }, + }, + ); + + if (!quote.success) { + throw new Error(quote.message); + } + + return mapKadoQuoteToQuoteResponse({ quote, sellAsset, buyAsset }); + } catch (_) { + throw new Error("core_swap_quote_error"); + } + } + + async function getBlockchains() { + const response = await RequestClient.get( + "https://api.kado.money/v1/ramp/blockchains", + ); + + if (!response.success) { + throw new Error(response.message); + } + + return response.data.blockchains; + } + + async function getAssets() { + const response = await RequestClient.get<{ + success: boolean; + message: string; + data: { + assets: { + _id: string; + name: string; + description: string; + label: string; + symbol: string; + supportedProviders: string[]; + stablecoin: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + }[]; + }; + }>("https://api.kado.money/v1/ramp/supported-assets"); + + if (!response.success) { + throw new Error(response.message); + } + + return response.data.assets; + } + + async function getOrderStatus(orderId: string) { + try { + const response = await RequestClient.get<{ + success: boolean; + message: string; + data: { + order: { + status: string; + // Add other relevant fields from the API response + }; + }; + }>(`https://api.kado.money/v2/public/orders/${orderId}`, { + headers: { + "X-Widget-Id": kadoApiKey, + }, + }); + + if (!response.success) { + throw new Error(response.message); + } + + return response.data.order; + } catch (_error) { + throw new Error("Failed to get order status"); + } + } + + function getKadoWidgetUrl({ + sellAsset, + buyAsset, + supportedAssets, + recipient, + networkList, + type, + typeList, + widgetMode, + }: { + sellAsset: AssetValue; + buyAsset: AssetValue; + supportedAssets: AssetValue[]; + recipient: string; + networkList: Chain[]; + type: "BUY" | "SELL"; + typeList: "BUY" | "SELL"; + widgetMode: "minimal" | "full"; + }) { + const urlParams = new URLSearchParams({ + onPayAmount: sellAsset.getValue("string"), + onPayCurrency: sellAsset.symbol, + onRevCurrency: buyAsset.symbol, + cryptoList: supportedAssets.map((asset) => asset.symbol).join(","), + onToAddress: recipient, + network: ChainToKadoChain(buyAsset.chain).toUpperCase(), + networkList: networkList.map((chain) => ChainToKadoChain(chain).toUpperCase()).join(","), + product: type, + productList: typeList, + mode: widgetMode, + }); + + return `https://app.kado.money/?${urlParams.toString()}`; + } + + return { + fetchProviderQuote, + getBlockchains, + getAssets, + getOrderStatus, + getKadoWidgetUrl, + supportedSwapkitProviders: [ProviderName.KADO], + }; +} + +export const KadoPlugin = { kado: { plugin } } as const; diff --git a/packages/plugins/kado/src/types.ts b/packages/plugins/kado/src/types.ts new file mode 100644 index 000000000..ed3078fd1 --- /dev/null +++ b/packages/plugins/kado/src/types.ts @@ -0,0 +1,212 @@ +import type { SupportedKadoChain } from "./helpers"; + +export const KadoSupportedFiatCurrencies = [ + "USD", + "CAD", + "GBP", + "EUR", + "MXN", + "COP", + "INR", + "CHF", + "AUD", + "ARS", + "BRL", + "CLP", + "JPY", + "KRW", + "PEN", + "PHP", + "SGD", + "TRY", + "UYU", + "TWD", + "VND", + "CRC", + "SEK", + "PLN", + "DKK", + "NOK", + "NZD", +] as const; + +export type KadoFiatCurrency = (typeof KadoSupportedFiatCurrencies)[number]; + +export type KadoFiatMethod = + | "ach" + | "debit_card" + | "credit_card" + | "apple_pay_credit" + | "apple_pay_debit" + | "wire" + | "sepa" + | "pix" + | "koywe"; + +export type KadoQuoteRequest = { + transactionType: "buy" | "sell"; + fiatMethod: KadoFiatMethod; + partner: "fortress"; + amount: string; + asset: string; + blockchain: string; + currency: KadoFiatCurrency; +}; + +export type KadoAsset = { + _id: string; + name: string; + description: string; + label: string; + symbol: string; + supportedProviders: string[]; + stablecoin: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + displayPrecision: number; + usesAvaxRouter: boolean; + squidChainId: string; + coingeckoId: string; + usesAxelarBridge: boolean; + squidAssetId: string; + address: string; + blockExplorerURI: string; + decimals: number; + officialChainId: keyof typeof SupportedKadoChain; + precision: number; + rampProducts: string[]; + wallets: string[]; + rpcURI: string; + usesPolygonFulfillment: boolean; + usesOsmoRouter: boolean; + ibcChannelIdOffRamp: number; + ibcChannelIdOnRamp: number; + osmoPfmChannel: number; + osmoPfmReceiver: string; + ibcDenom: string; + isNative: boolean; + avgOffRampTimeInSeconds: number; + avgOnRampTimeInSeconds: number; + providers: string[]; + trustekAssetId: string; + trustekNetworkId: string; + kycLevels: string[]; +}; + +export type KadoBlockchainsResponse = { + success: boolean; + message: string; + data: { + blockchains: { + _id: string; + supportedEnvironment: string; + network: string; + origin: string; + label: string; + associatedAssets: KadoAsset[]; + avgTransactionTimeSeconds: number; + usesAvaxRouter: boolean; + liveOnRamp: boolean; + createdAt: string; + updatedAt: string; + __v: number; + priority: number; + }[]; + }; +}; + +export type KadoSupportedAssetsResponse = { + success: boolean; + message: string; + data: { + assets: KadoAsset[]; + }; +}; + +export type KadoQuoteResponse = { + success: boolean; + message: string; + data: { + request: { + transactionType: string; + fiatMethod: KadoFiatMethod; + partner: string; + amount: number; + asset: string; + blockchain: keyof typeof SupportedKadoChain; + currency: KadoFiatCurrency; + reverse: false; + ipCountry: string; + }; + quote: { + asset: string; + baseAmount: { + amount: number; + currency: KadoFiatCurrency; + }; + price: { + amount: number; + price: number; + symbol: string; + unit: string; + }; + bridgeFee: { + amount: number; + currency: KadoFiatCurrency; + originalAmount: number; + promotionModifier: number; + }; + receiveAmountAfterFees: { + originalAmount: number; + amount: number; + currency: KadoFiatCurrency; + }; + receiveUnitCountAfterFees: { + amount: number; + currency: KadoFiatCurrency; + }; + feeType: string; + minValue: { + amount: number; + unit: string; + }; + maxValue: { + amount: number; + unit: string; + }; + receive: { + amount: number; + originalAmount: number; + symbol: string; + unit: string; + unitCount: number; + }; + networkFee: { + amount: number; + currency: KadoFiatCurrency; + originalAmount: number; + promotionModifier: number; + }; + processingFee: { + amount: number; + currency: KadoFiatCurrency; + originalAmount: number; + promotionModifier: number; + }; + totalFee: { + amount: number; + currency: KadoFiatCurrency; + originalAmount: number; + }; + smartContractFee: { + amount: number; + currency: KadoFiatCurrency; + originalAmount: number; + promotionModifier: number; + }; + }; + }; +}; diff --git a/packages/plugins/kado/tsconfig.json b/packages/plugins/kado/tsconfig.json new file mode 100644 index 000000000..46d921163 --- /dev/null +++ b/packages/plugins/kado/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../../tools/typescript/base.json", + "include": ["src", "./build.ts", "../../../tools/typescript/typings.d.ts"] +} diff --git a/packages/plugins/radix/src/index.ts b/packages/plugins/radix/src/index.ts index 800095539..f4f0d75f2 100644 --- a/packages/plugins/radix/src/index.ts +++ b/packages/plugins/radix/src/index.ts @@ -29,7 +29,7 @@ function plugin({ getWallet }: SwapKitPluginParams) { // await convertInstructionsToManifest({ network: RadixMainnet })( // route.transaction as Instructions, // ) - // ).value as string; + // ).value as string;c return wallet.signAndBroadcast({ manifest: route.tx as string, }); diff --git a/packages/plugins/thorchain/src/tcPlugin.ts b/packages/plugins/thorchain/src/tcPlugin.ts index b52076e3f..0dc4bc3e9 100644 --- a/packages/plugins/thorchain/src/tcPlugin.ts +++ b/packages/plugins/thorchain/src/tcPlugin.ts @@ -13,6 +13,7 @@ import { TCBscDepositABI, TCEthereumVaultAbi, type UTXOChain, + type WalletChain, getMemoForLoan, } from "@swapkit/helpers"; @@ -143,7 +144,7 @@ function plugin({ getWallet, stagenet = false }: SwapKitPluginParams) { getMemoForLoan(type === "open" ? MemoType.OPEN_LOAN : MemoType.CLOSE_LOAN, { asset: assetValue.toString(), minAmount: minAmount.toString(), - address: getWallet(assetValue.chain).address, + address: getWallet(assetValue.chain as WalletChain).address, }), }); } diff --git a/packages/swapkit/core/src/client.ts b/packages/swapkit/core/src/client.ts index 60d24e187..5e6bf5ea0 100644 --- a/packages/swapkit/core/src/client.ts +++ b/packages/swapkit/core/src/client.ts @@ -110,7 +110,7 @@ export function SwapKit< return plugin; } - function addChain(connectWallet: ChainWallet) { + function addChain(connectWallet: ChainWallet) { const currentWallet = getWallet(connectWallet.chain); connectedWallets[connectWallet.chain] = { ...currentWallet, ...connectWallet }; @@ -169,7 +169,7 @@ export function SwapKit< /** * @Public */ - function getWallet(chain: T) { + function getWallet(chain: T) { return connectedWallets[chain]; } @@ -177,7 +177,7 @@ export function SwapKit< return { ...connectedWallets }; } - function getAddress(chain: T) { + function getAddress(chain: T) { return getWallet(chain)?.address || ""; } @@ -189,7 +189,7 @@ export function SwapKit< return approve({ assetValue, contractAddress, type: ApproveMode.CheckOnly }); } - function disconnectChain(chain: T) { + function disconnectChain(chain: T) { const wallet = getWallet(chain); wallet?.disconnect?.(); delete connectedWallets[chain]; @@ -201,7 +201,7 @@ export function SwapKit< } } - function getBalance( + function getBalance( chain: T, refresh?: R, ): ConditionalAssetValueReturn { @@ -222,7 +222,7 @@ export function SwapKit< }); } - async function getWalletWithBalance(chain: T, potentialScamFilter = true) { + async function getWalletWithBalance(chain: T, potentialScamFilter = true) { const defaultBalance = [AssetValue.from({ chain })]; const wallet = getWallet(chain); @@ -260,14 +260,14 @@ export function SwapKit< assetValue, ...params }: UTXOTransferParams | EVMTransferParams | CosmosTransferParams) { - const chain = assetValue.chain as WalletChain; + const chain = assetValue.chain as Exclude; const wallet = getWallet(chain); if (!wallet) throw new SwapKitError("core_wallet_connection_not_found"); return wallet.transfer({ ...params, assetValue }); } - function signMessage({ chain, message }: { chain: Chain; message: string }) { + function signMessage({ chain, message }: { chain: WalletChain; message: string }) { const wallet = getWallet(chain); if (!wallet) throw new SwapKitError("core_wallet_connection_not_found"); @@ -321,7 +321,8 @@ export function SwapKit< const { assetValue } = params; const { chain } = assetValue; - if (!getWallet(chain)) throw new SwapKitError("core_wallet_connection_not_found"); + if (!getWallet(chain as WalletChain)) + throw new SwapKitError("core_wallet_connection_not_found"); const baseValue = AssetValue.from({ chain }); diff --git a/packages/swapkit/helpers/src/helpers/asset.ts b/packages/swapkit/helpers/src/helpers/asset.ts index 0de865fab..9b4875e4f 100644 --- a/packages/swapkit/helpers/src/helpers/asset.ts +++ b/packages/swapkit/helpers/src/helpers/asset.ts @@ -278,3 +278,27 @@ export async function findAssetBy( return; } + +export const blockTimes = { + [Chain.Arbitrum]: 1, + [Chain.Avalanche]: 3, + [Chain.Base]: 1, + [Chain.BinanceSmartChain]: 3, + [Chain.Bitcoin]: 600, + [Chain.BitcoinCash]: 600, + [Chain.Chainflip]: 5, + [Chain.Cosmos]: 1.5, + [Chain.Dash]: 150, + [Chain.Dogecoin]: 600, + [Chain.Ethereum]: 12.5, + [Chain.Fiat]: 60, + [Chain.Kujira]: 2.2, + [Chain.Litecoin]: 150, + [Chain.Maya]: 6, + [Chain.Optimism]: 1, + [Chain.Polkadot]: 6, + [Chain.Polygon]: 2.1, + [Chain.Radix]: 5, + [Chain.Solana]: 1, + [Chain.THORChain]: 6, +}; diff --git a/packages/swapkit/helpers/src/types/chains.ts b/packages/swapkit/helpers/src/types/chains.ts index 4cf0c0669..02866fb49 100644 --- a/packages/swapkit/helpers/src/types/chains.ts +++ b/packages/swapkit/helpers/src/types/chains.ts @@ -9,6 +9,7 @@ export enum Chain { Dash = "DASH", Dogecoin = "DOGE", Ethereum = "ETH", + Fiat = "FIAT", Kujira = "KUJI", Litecoin = "LTC", Maya = "MAYA", @@ -26,7 +27,7 @@ export enum StagenetChain { Maya = "MAYA_STAGENET", } -export type WalletChain = Exclude; +export type WalletChain = Exclude; export enum ChainId { Arbitrum = "42161", @@ -46,6 +47,7 @@ export enum ChainId { Kujira = "kaiyo-1", Ethereum = "1", EthereumHex = "0x1", + Fiat = "fiat", Litecoin = "litecoin", Maya = "mayachain-mainnet-v1", MayaStagenet = "mayachain-stagenet-v1", @@ -76,6 +78,7 @@ export const ChainIdToChain: Record = { [ChainId.Dash]: Chain.Dash, [ChainId.Dogecoin]: Chain.Dogecoin, [ChainId.EthereumHex]: Chain.Ethereum, + [ChainId.Fiat]: Chain.Fiat, [ChainId.Kujira]: Chain.Kujira, [ChainId.Ethereum]: Chain.Ethereum, [ChainId.Litecoin]: Chain.Litecoin, @@ -107,6 +110,7 @@ export const BaseDecimal: Record = { DOGE: 8, DOT: 10, ETH: 18, + FIAT: 2, FLIP: 18, GAIA: 6, KUJI: 6, @@ -131,6 +135,7 @@ export const BlockTimes: Record, number> = { [Chain.Dash]: 150, [Chain.Dogecoin]: 600, [Chain.Ethereum]: 12.5, + [Chain.Fiat]: 60, [Chain.Kujira]: 2.2, [Chain.Litecoin]: 150, [Chain.Maya]: 6, @@ -213,6 +218,7 @@ export const RPC_URLS: Record = { [Chain.Dash]: "https://dash-rpc.publicnode.com", [Chain.Dogecoin]: "https://node-router.thorswap.net/dogecoin", [Chain.Ethereum]: "https://ethereum-rpc.publicnode.com", + [Chain.Fiat]: "", [Chain.Kujira]: "https://rpc-kujira.synergynodes.com/", [Chain.Litecoin]: "https://node-router.thorswap.net/litecoin", [Chain.Maya]: "https://tendermint.mayachain.info", @@ -250,6 +256,7 @@ export const FALLBACK_URLS: Record = { [Chain.Dash]: ["https://dash-rpc.publicnode.com"], [Chain.Dogecoin]: ["https://doge.getblock.io/mainnet", "https://dogecoin.publicnode.com"], [Chain.Ethereum]: ["https://eth.llamarpc.com", "https://rpc.ankr.com/eth"], + [Chain.Fiat]: [], [Chain.Kujira]: ["https://kujira-rpc.polkachu.com", "https://kujira-rpc.ibs.team"], [Chain.Litecoin]: ["https://ltc.getblock.io/mainnet", "https://litecoin.publicnode.com"], [Chain.Maya]: ["https://tendermint.mayachain.info", "https://maya-tendermint.publicnode.com"], @@ -278,6 +285,7 @@ export const EXPLORER_URLS: Record = { [Chain.Dash]: "https://blockchair.com/dash", [Chain.Dogecoin]: "https://blockchair.com/dogecoin", [Chain.Ethereum]: "https://etherscan.io", + [Chain.Fiat]: "", [Chain.Kujira]: "https://finder.kujira.network/kaiyo-1", [Chain.Litecoin]: "https://blockchair.com/litecoin", [Chain.Maya]: "https://www.mayascan.org", diff --git a/packages/swapkit/helpers/src/types/commonTypes.ts b/packages/swapkit/helpers/src/types/commonTypes.ts index 69f014922..86af734be 100644 --- a/packages/swapkit/helpers/src/types/commonTypes.ts +++ b/packages/swapkit/helpers/src/types/commonTypes.ts @@ -1,5 +1,5 @@ import type { RadixNetwork } from "@swapkit/toolbox-radix"; -import type { Chain } from "./chains"; +import type { Chain, WalletChain } from "./chains"; import type { ChainApis } from "./sdk"; import type { ChainWallet } from "./wallet"; @@ -78,10 +78,15 @@ export type ConnectConfig = SwapkitConfig & { applicationVersion: string; network: RadixNetwork; }; + + /** + * @optional for setting the kado api key + */ + kadoApiKey?: string; }; export type ConnectWalletParams = { - addChain: (params: ChainWallet & M) => void; + addChain: (params: ChainWallet & M) => void; apis: ChainApis; config: ConnectConfig; rpcUrls: { [chain in Chain]?: string }; diff --git a/packages/swapkit/helpers/src/types/derivationPath.ts b/packages/swapkit/helpers/src/types/derivationPath.ts index 19f1ae2b4..4b8942f17 100644 --- a/packages/swapkit/helpers/src/types/derivationPath.ts +++ b/packages/swapkit/helpers/src/types/derivationPath.ts @@ -55,7 +55,8 @@ export const NetworkDerivationPath: Record = { THOR: [44, 931, 0, 0, 0], // Polkadot and related network derivation path is not number based - XRD: [0, 0, 0, 0, 0], DOT: [0, 0, 0, 0, 0], + FIAT: [0, 0, 0, 0, 0], FLIP: [0, 0, 0, 0, 0], + XRD: [0, 0, 0, 0, 0], }; diff --git a/packages/swapkit/helpers/src/types/quotes.ts b/packages/swapkit/helpers/src/types/quotes.ts index d8bac3854..c3c71785c 100644 --- a/packages/swapkit/helpers/src/types/quotes.ts +++ b/packages/swapkit/helpers/src/types/quotes.ts @@ -159,6 +159,7 @@ export enum ProviderName { TRADERJOE_V2 = "TRADERJOE_V2", UNISWAP_V2 = "UNISWAP_V2", UNISWAP_V3 = "UNISWAP_V3", + KADO = "KADO", } export enum FeeTypeEnum { diff --git a/packages/swapkit/helpers/src/types/wallet.ts b/packages/swapkit/helpers/src/types/wallet.ts index 6f68f6a3a..04fa797e4 100644 --- a/packages/swapkit/helpers/src/types/wallet.ts +++ b/packages/swapkit/helpers/src/types/wallet.ts @@ -7,7 +7,7 @@ import type { UTXOWallets } from "@swapkit/toolbox-utxo"; import type { Eip1193Provider } from "ethers"; import type { AssetValue } from "../modules/assetValue"; -import type { Chain } from "./chains"; +import type { Chain, WalletChain } from "./chains"; import type { ConnectWalletParams } from "./commonTypes"; declare global { @@ -66,9 +66,9 @@ export type ChainWallet = { signMessage?: (message: string) => Promise; }; -export type EmptyWallet = { [key in Chain]?: unknown }; +export type EmptyWallet = { [key in WalletChain]?: unknown }; export type BaseWallet> = { - [key in Chain]: ChainWallet & (T extends EmptyWallet ? T[key] : never); + [key in WalletChain]: ChainWallet & (T extends EmptyWallet ? T[key] : never); }; export type FullWallet = BaseWallet< @@ -91,7 +91,7 @@ export type SwapKitWallet = ( ) => (...connectParams: ConnectParams) => boolean | Promise; export type SwapKitPluginParams = { - getWallet: (chain: T) => FullWallet[T]; + getWallet: (chain: T) => FullWallet[T]; stagenet?: boolean; config: Config; }; diff --git a/packages/swapkit/sdk/package.json b/packages/swapkit/sdk/package.json index 299955105..02cb87a6e 100644 --- a/packages/swapkit/sdk/package.json +++ b/packages/swapkit/sdk/package.json @@ -5,6 +5,7 @@ "@swapkit/core": "workspace:*", "@swapkit/plugin-chainflip": "workspace:*", "@swapkit/plugin-evm": "workspace:*", + "@swapkit/plugin-kado": "workspace:*", "@swapkit/plugin-radix": "workspace:*", "@swapkit/plugin-thorchain": "workspace:*", "@swapkit/tokens": "workspace:*", diff --git a/packages/swapkit/sdk/src/index.ts b/packages/swapkit/sdk/src/index.ts index 578b22424..a9223c9a9 100644 --- a/packages/swapkit/sdk/src/index.ts +++ b/packages/swapkit/sdk/src/index.ts @@ -1,6 +1,7 @@ import { SwapKit, type SwapKitParams } from "@swapkit/core"; import { ChainflipPlugin } from "@swapkit/plugin-chainflip"; import { EVMPlugin } from "@swapkit/plugin-evm"; +import { KadoPlugin } from "@swapkit/plugin-kado"; import { RadixPlugin } from "@swapkit/plugin-radix"; import { MayachainPlugin, ThorchainPlugin } from "@swapkit/plugin-thorchain"; import { wallets as defaultWallets } from "@swapkit/wallets"; @@ -11,6 +12,7 @@ export * from "@swapkit/tokens"; const defaultPlugins = { ...ChainflipPlugin, ...EVMPlugin, + ...KadoPlugin, ...MayachainPlugin, ...ThorchainPlugin, ...RadixPlugin, diff --git a/packages/swapkit/tokens/src/index.ts b/packages/swapkit/tokens/src/index.ts index 58308be38..c8e3162fe 100644 --- a/packages/swapkit/tokens/src/index.ts +++ b/packages/swapkit/tokens/src/index.ts @@ -1,6 +1,7 @@ export { list as CaviarV1List } from "./tokenLists/caviar_v1"; export { list as ChainflipList } from "./tokenLists/chainflip"; export { list as JupiterList } from "./tokenLists/jupiter"; +export { list as KadoList } from "./tokenLists/kado"; export { list as MayaList } from "./tokenLists/mayachain"; // export { list as OciswapV1List } from "./tokenLists/ociswap_v1"; export { list as OneInchList } from "./tokenLists/oneinch"; diff --git a/packages/swapkit/tokens/src/tokenLists/kado.ts b/packages/swapkit/tokens/src/tokenLists/kado.ts new file mode 100644 index 000000000..86abc33b0 --- /dev/null +++ b/packages/swapkit/tokens/src/tokenLists/kado.ts @@ -0,0 +1,276 @@ +export const list = { + provider: "KADO", + chainId: "fiat", + name: "KADO", + timestamp: "2024-09-25T15:31:06.827Z", + version: { + major: 1, + minor: 0, + patch: 0, + }, + keywords: [], + count: 27, + tokens: [ + { + chain: "BTC", + chainId: "bitcoin", + decimals: 8, + identifier: "BTC.BTC", + logoURI: "", + symbol: "BTC", + ticker: "BTC", + }, + { + chain: "ETH", + chainId: "1", + decimals: 18, + identifier: "ETH.ETH", + logoURI: "", + symbol: "ETH", + ticker: "ETH", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.USD", + logoURI: "", + symbol: "USD", + ticker: "USD", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.CAD", + logoURI: "", + symbol: "CAD", + ticker: "CAD", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.GBP", + logoURI: "", + symbol: "GBP", + ticker: "GBP", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.EUR", + logoURI: "", + symbol: "EUR", + ticker: "EUR", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.MXN", + logoURI: "", + symbol: "MXN", + ticker: "MXN", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.COP", + logoURI: "", + symbol: "COP", + ticker: "COP", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.INR", + logoURI: "", + symbol: "INR", + ticker: "INR", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.CHF", + logoURI: "", + symbol: "CHF", + ticker: "CHF", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.AUD", + logoURI: "", + symbol: "AUD", + ticker: "AUD", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.ARS", + logoURI: "", + symbol: "ARS", + ticker: "ARS", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.BRL", + logoURI: "", + symbol: "BRL", + ticker: "BRL", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.CLP", + logoURI: "", + symbol: "CLP", + ticker: "CLP", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.JPY", + logoURI: "", + symbol: "JPY", + ticker: "JPY", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.KRW", + logoURI: "", + symbol: "KRW", + ticker: "KRW", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.PEN", + logoURI: "", + symbol: "PEN", + ticker: "PEN", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.PHP", + logoURI: "", + symbol: "PHP", + ticker: "PHP", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.SGD", + logoURI: "", + symbol: "SGD", + ticker: "SGD", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.TRY", + logoURI: "", + symbol: "TRY", + ticker: "TRY", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.UYU", + logoURI: "", + symbol: "UYU", + ticker: "UYU", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.TWD", + logoURI: "", + symbol: "TWD", + ticker: "TWD", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.VND", + logoURI: "", + symbol: "VND", + ticker: "VND", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.CRC", + logoURI: "", + symbol: "CRC", + ticker: "CRC", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.SEK", + logoURI: "", + symbol: "SEK", + ticker: "SEK", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.PLN", + logoURI: "", + symbol: "PLN", + ticker: "PLN", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.DKK", + logoURI: "", + symbol: "DKK", + ticker: "DKK", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.NOK", + logoURI: "", + symbol: "NOK", + ticker: "NOK", + }, + { + chain: "FIAT", + chainId: "fiat", + decimals: 2, + identifier: "FIAT.NZD", + logoURI: "", + symbol: "NZD", + ticker: "NZD", + }, + ], +} as const; diff --git a/packages/wallets/ledger/src/ledgerLive.ts b/packages/wallets/ledger/src/ledgerLive.ts index 51a333e9c..f13f541fb 100644 --- a/packages/wallets/ledger/src/ledgerLive.ts +++ b/packages/wallets/ledger/src/ledgerLive.ts @@ -14,9 +14,10 @@ import { FeeOption, SwapKitError, SwapKitNumber, + type WalletChain, WalletOption, setRequestClientConfig, -} from "@swapkit/sdk"; +} from "@swapkit/helpers"; import { ETHToolbox, getProvider } from "@swapkit/toolbox-evm"; import type { UTXOTransferParams } from "@swapkit/toolbox-utxo"; import { BigNumber as BigNumberJS } from "bignumber.js"; @@ -37,14 +38,14 @@ export enum LedgerLiveChain { ATOM = "cosmos", } -export const LEDGER_LIVE_SUPPORTED_CHAINS: Chain[] = [ +export const LEDGER_LIVE_SUPPORTED_CHAINS = [ Chain.Bitcoin, Chain.Ethereum, Chain.Cosmos, Chain.Litecoin, Chain.Dogecoin, Chain.BitcoinCash, -]; +] as WalletChain[]; export const ChainToLedgerLiveChain: Partial> = { [Chain.Arbitrum]: LedgerLiveChain.ARB, diff --git a/playgrounds/nextjs/package.json b/playgrounds/nextjs/package.json index 69dcccfb1..b16211bd0 100644 --- a/playgrounds/nextjs/package.json +++ b/playgrounds/nextjs/package.json @@ -35,6 +35,7 @@ "@swapkit/core": "workspace:*", "@swapkit/plugin-chainflip": "workspace:*", "@swapkit/plugin-evm": "workspace:*", + "@swapkit/plugin-kado": "workspace:*", "@swapkit/plugin-thorchain": "workspace:*", "@swapkit/tokens": "workspace:*", "@swapkit/wallets": "workspace:*", diff --git a/playgrounds/nextjs/src/app/offRamp/page.tsx b/playgrounds/nextjs/src/app/offRamp/page.tsx new file mode 100644 index 000000000..8c97cd905 --- /dev/null +++ b/playgrounds/nextjs/src/app/offRamp/page.tsx @@ -0,0 +1,17 @@ +"use client"; + +import { Card, CardDescription, CardTitle } from "~/components/ui/card"; +// import { useSwapKit } from "~/lib/swapKit"; + +export default function Send() { + // const { swapKit } = useSwapKit(); + + return ( +

+ + Send + Send + +
+ ); +} diff --git a/playgrounds/nextjs/src/lib/swapKit.ts b/playgrounds/nextjs/src/lib/swapKit.ts index 8103d4618..a0d70b3a5 100644 --- a/playgrounds/nextjs/src/lib/swapKit.ts +++ b/playgrounds/nextjs/src/lib/swapKit.ts @@ -19,6 +19,7 @@ export const useSwapKit = () => { const loadSwapKit = async () => { const { SwapKit } = await import("@swapkit/core"); const { ChainflipPlugin } = await import("@swapkit/plugin-chainflip"); + const { KadoPlugin } = await import("@swapkit/plugin-kado"); const { ThorchainPlugin, MayachainPlugin } = await import("@swapkit/plugin-thorchain"); const { wallets } = await import("@swapkit/wallets"); @@ -41,7 +42,7 @@ export const useSwapKit = () => { }, }, wallets, - plugins: { ...ThorchainPlugin, ...ChainflipPlugin, ...MayachainPlugin }, + plugins: { ...ThorchainPlugin, ...ChainflipPlugin, ...MayachainPlugin, ...KadoPlugin }, }); setSwapKit(swapKitClient); diff --git a/playgrounds/vite/src/App.tsx b/playgrounds/vite/src/App.tsx index ea1b6249b..4ba395a34 100644 --- a/playgrounds/vite/src/App.tsx +++ b/playgrounds/vite/src/App.tsx @@ -1,4 +1,4 @@ -import { AssetValue, type Chain, type FullWallet } from "@swapkit/core"; +import { AssetValue, type FullWallet, type WalletChain } from "@swapkit/core"; import { useCallback, useEffect, useMemo, useState } from "react"; import { WalletWidget } from "@swapkit/wallet-exodus"; @@ -14,7 +14,7 @@ import { getSwapKitClient } from "./swapKitClient"; const apiKeys = ["walletConnectProjectId"] as const; -type WalletDataType = FullWallet[Chain] | FullWallet[Chain][] | null; +type WalletDataType = FullWallet[WalletChain] | FullWallet[WalletChain][] | null; const App = () => { const [widgetType, setWidgetType] = useState<"swap" | "loan" | "earn">("swap"); @@ -62,7 +62,7 @@ const App = () => { [inputAsset, outputAsset], ); - const disconnectChain = (chain: Chain) => { + const disconnectChain = (chain: WalletChain) => { if (!skClient) return; skClient.disconnectChain(chain); setWallet(Object.values(skClient.getAllWallets())); @@ -154,15 +154,17 @@ const App = () => { key={`${walletData?.address}-${walletData?.balance?.[0]?.chain}`} setAsset={setAsset} walletData={walletData} - disconnect={() => disconnectChain(walletData?.balance?.[0]?.chain as Chain)} + disconnect={() => + disconnectChain(walletData?.balance?.[0]?.chain as WalletChain) + } /> )) ) : ( disconnectChain(wallet?.balance?.[0]?.chain as Chain)} + walletData={wallet as FullWallet[WalletChain]} + disconnect={() => disconnectChain(wallet?.balance?.[0]?.chain as WalletChain)} /> )} diff --git a/playgrounds/vite/src/Send/index.tsx b/playgrounds/vite/src/Send/index.tsx index ab8b51390..c5494519e 100644 --- a/playgrounds/vite/src/Send/index.tsx +++ b/playgrounds/vite/src/Send/index.tsx @@ -1,4 +1,4 @@ -import type { AssetValue, WalletChain } from "@swapkit/core"; +import type { AssetValue, Chain, WalletChain } from "@swapkit/core"; import { useCallback, useState } from "react"; import type { SwapKitClient } from "../swapKitClient"; @@ -22,13 +22,15 @@ export default function Send({ const handleSend = useCallback(async () => { if (!(inputAsset && inputAssetValue?.gt(0) && skClient)) return; - const from = skClient.getAddress(inputAsset.chain); - const txHash = await skClient.getWallet(inputAssetValue.chain as WalletChain).transfer({ - from, - assetValue: inputAssetValue, - memo: "", - recipient, - }); + const from = skClient.getAddress(inputAsset.chain as WalletChain); + const txHash = await skClient + .getWallet(inputAssetValue.chain as Exclude) + .transfer({ + from, + assetValue: inputAssetValue, + memo: "", + recipient, + }); window.open( `${skClient.getExplorerTxUrl({ chain: inputAssetValue.chain, txHash: txHash as string })}`, diff --git a/playgrounds/vite/src/Swap/SwapInputs.tsx b/playgrounds/vite/src/Swap/SwapInputs.tsx index aac6ad490..0d59ba60c 100644 --- a/playgrounds/vite/src/Swap/SwapInputs.tsx +++ b/playgrounds/vite/src/Swap/SwapInputs.tsx @@ -1,5 +1,11 @@ "use client"; -import type { AssetValue, EVMTransaction, QuoteResponseRoute, SwapKit } from "@swapkit/sdk"; +import type { + AssetValue, + EVMTransaction, + QuoteResponseRoute, + SwapKit, + WalletChain, +} from "@swapkit/sdk"; import { ProviderName, SwapKitApi, SwapKitNumber } from "@swapkit/sdk"; import { useCallback, useState } from "react"; @@ -34,8 +40,8 @@ export const SwapInputs = ({ skClient, inputAsset, outputAsset, handleSwap }: Pr setLoading(true); setRoutes([]); - const sourceAddress = skClient.getAddress(inputAsset.chain); - const destinationAddress = skClient.getAddress(outputAsset.chain); + const sourceAddress = skClient.getAddress(inputAsset.chain as WalletChain); + const destinationAddress = skClient.getAddress(outputAsset.chain as WalletChain); // const providers = Object.values(ProviderName); try { diff --git a/playgrounds/vite/src/TNS/index.tsx b/playgrounds/vite/src/TNS/index.tsx index 8f7e0a8c1..a2af1552e 100644 --- a/playgrounds/vite/src/TNS/index.tsx +++ b/playgrounds/vite/src/TNS/index.tsx @@ -1,9 +1,15 @@ -import { AssetValue, Chain, SwapKitApi, type THORNameDetails } from "@swapkit/sdk"; +import { + AssetValue, + Chain, + SwapKitApi, + type THORNameDetails, + type WalletChain, +} from "@swapkit/sdk"; import { useCallback, useState } from "react"; import type { SwapKitClient } from "../swapKitClient"; export default function TNS({ skClient }: { skClient: SwapKitClient }) { - const [selectedChain, setSelectedChain] = useState(Chain.THORChain); + const [selectedChain, setSelectedChain] = useState(Chain.THORChain); const [name, setName] = useState(""); const [tnsSearch, setTnsSearch] = useState(""); const [tnsDetail, setTnsDetail] = useState(); @@ -55,7 +61,7 @@ export default function TNS({ skClient }: { skClient: SwapKitClient }) { >
- setSelectedChain(e.target.value as WalletChain)}> {Object.values(Chain).map((chain) => ( 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 w`|)J(*?6)viPAvL>n+a diff --git a/packages/swapkit/helpers/src/helpers/web3wallets.ts b/packages/swapkit/helpers/src/helpers/web3wallets.ts index 61cfb54d5..a13e210f5 100644 --- a/packages/swapkit/helpers/src/helpers/web3wallets.ts +++ b/packages/swapkit/helpers/src/helpers/web3wallets.ts @@ -129,7 +129,7 @@ export const switchEVMWalletNetwork = (provider: BrowserProvider, chainId = Chai export const addAccountsChangedCallback = (callback: () => void) => { window.ethereum?.on("accountsChanged", () => callback()); - // @ts-expect-error that should be implemented in xdefi and hooked up via swapkit core + // @ts-expect-error that should be implemented in ctrl and hooked up via swapkit core window.xfi?.ethereum.on("accountsChanged", () => callback()); }; @@ -139,7 +139,7 @@ export const getETHDefaultWallet = () => { if (isTrust) return WalletOption.TRUSTWALLET_WEB; if (isBraveWallet) return WalletOption.BRAVE; if (overrideIsMetaMask && selectedProvider?.isCoinbaseWallet) return WalletOption.COINBASE_WEB; - if (__XDEFI) WalletOption.XDEFI; + if (__XDEFI) WalletOption.CTRL; return WalletOption.METAMASK; }; @@ -149,8 +149,8 @@ export const isDetected = (walletOption: WalletOption) => { export const listWeb3EVMWallets = () => { const metamaskEnabled = window?.ethereum && !window.ethereum?.isBraveWallet; - // @ts-ignore that should be implemented in xdefi and hooked up via swapkit core - const xdefiEnabled = window?.xfi || window?.ethereum?.__XDEFI; + // @ts-ignore that should be implemented in ctrl and hooked up via swapkit core + const ctrlEnabled = window?.xfi || window?.ethereum?.__XDEFI; const braveEnabled = window?.ethereum?.isBraveWallet; const trustEnabled = window?.ethereum?.isTrust || window?.trustwallet; const coinbaseEnabled = @@ -160,7 +160,7 @@ export const listWeb3EVMWallets = () => { const wallets = []; if (metamaskEnabled) wallets.push(WalletOption.METAMASK); - if (xdefiEnabled) wallets.push(WalletOption.XDEFI); + if (ctrlEnabled) wallets.push(WalletOption.CTRL); if (braveEnabled) wallets.push(WalletOption.BRAVE); if (trustEnabled) wallets.push(WalletOption.TRUSTWALLET_WEB); if (coinbaseEnabled) wallets.push(WalletOption.COINBASE_WEB); diff --git a/packages/swapkit/helpers/src/modules/swapKitError.ts b/packages/swapkit/helpers/src/modules/swapKitError.ts index e45cb767f..472f33432 100644 --- a/packages/swapkit/helpers/src/modules/swapKitError.ts +++ b/packages/swapkit/helpers/src/modules/swapKitError.ts @@ -16,7 +16,7 @@ const errorCodes = { * Core - Wallet */ core_wallet_connection_not_found: 10100, - core_wallet_xdefi_not_installed: 10101, + core_wallet_ctrl_not_installed: 10101, core_wallet_evmwallet_not_installed: 10102, core_wallet_walletconnect_not_installed: 10103, core_wallet_keystore_not_installed: 10104, @@ -74,10 +74,10 @@ const errorCodes = { wallet_ledger_device_not_found: 20104, wallet_ledger_device_locked: 20105, wallet_phantom_not_found: 20201, - wallet_xdefi_not_found: 20301, - wallet_xdefi_send_transaction_no_address: 20302, - wallet_xdefi_contract_address_not_provided: 20303, - wallet_xdefi_asset_not_defined: 20304, + wallet_ctrl_not_found: 20301, + wallet_ctrl_send_transaction_no_address: 20302, + wallet_ctrl_contract_address_not_provided: 20303, + wallet_ctrl_asset_not_defined: 20304, wallet_walletconnect_project_id_not_specified: 20401, wallet_walletconnect_connection_not_established: 20402, wallet_walletconnect_namespace_not_supported: 20403, diff --git a/packages/swapkit/helpers/src/types/wallet.ts b/packages/swapkit/helpers/src/types/wallet.ts index 04fa797e4..408a4b1a0 100644 --- a/packages/swapkit/helpers/src/types/wallet.ts +++ b/packages/swapkit/helpers/src/types/wallet.ts @@ -29,6 +29,7 @@ export enum WalletOption { BRAVE = "BRAVE", COINBASE_MOBILE = "COINBASE_MOBILE", COINBASE_WEB = "COINBASE_WEB", + CTRL = "CTRL", EIP6963 = "EIP6963", EXODUS = "EXODUS", KEEPKEY = "KEEPKEY", @@ -48,7 +49,6 @@ export enum WalletOption { TALISMAN = "TALISMAN", TRUSTWALLET_WEB = "TRUSTWALLET_WEB", WALLETCONNECT = "WALLETCONNECT", - XDEFI = "XDEFI", } export enum LedgerErrorCode { diff --git a/packages/swapkit/wallets/package.json b/packages/swapkit/wallets/package.json index 2864b9199..bfe2c4474 100644 --- a/packages/swapkit/wallets/package.json +++ b/packages/swapkit/wallets/package.json @@ -2,6 +2,7 @@ "description": "SwapKit - Wallets", "dependencies": { "@swapkit/wallet-coinbase": "workspace:*", + "@swapkit/wallet-ctrl": "workspace:*", "@swapkit/wallet-evm-extensions": "workspace:*", "@swapkit/wallet-exodus": "workspace:*", "@swapkit/wallet-keepkey": "workspace:*", @@ -15,8 +16,7 @@ "@swapkit/wallet-radix": "workspace:*", "@swapkit/wallet-talisman": "workspace:*", "@swapkit/wallet-trezor": "workspace:*", - "@swapkit/wallet-wc": "workspace:*", - "@swapkit/wallet-xdefi": "workspace:*" + "@swapkit/wallet-wc": "workspace:*" }, "files": [ "src/", diff --git a/packages/swapkit/wallets/src/index.ts b/packages/swapkit/wallets/src/index.ts index 765cea995..7a3ef4974 100644 --- a/packages/swapkit/wallets/src/index.ts +++ b/packages/swapkit/wallets/src/index.ts @@ -1,4 +1,5 @@ import { coinbaseWallet } from "@swapkit/wallet-coinbase"; +import { ctrlWallet } from "@swapkit/wallet-ctrl"; import { evmWallet } from "@swapkit/wallet-evm-extensions"; import { exodusWallet } from "@swapkit/wallet-exodus"; import { keepkeyWallet } from "@swapkit/wallet-keepkey"; @@ -13,7 +14,6 @@ import { radixWallet } from "@swapkit/wallet-radix"; import { talismanWallet } from "@swapkit/wallet-talisman"; import { trezorWallet } from "@swapkit/wallet-trezor"; import { walletconnectWallet } from "@swapkit/wallet-wc"; -import { xdefiWallet } from "@swapkit/wallet-xdefi"; export const wallets = { ...coinbaseWallet, @@ -31,5 +31,5 @@ export const wallets = { ...talismanWallet, ...trezorWallet, ...walletconnectWallet, - ...xdefiWallet, + ...ctrlWallet, }; diff --git a/packages/swapkit/wizard/src/index.ts b/packages/swapkit/wizard/src/index.ts index 847da0e9a..73a9b24ca 100644 --- a/packages/swapkit/wizard/src/index.ts +++ b/packages/swapkit/wizard/src/index.ts @@ -34,7 +34,7 @@ enum Wallet { TALISMAN = "talisman", TREZOR = "trezor", WC = "wc", - XDEFI = "xdefi", + CTRL = "ctrl", EVM_EXTENSIONS = "evm-extensions", KEYSTORE = "keystore", } @@ -57,7 +57,7 @@ const walletOptions = [ { value: Wallet.TALISMAN, label: "Talisman" }, { value: Wallet.TREZOR, label: "Trezor", hint: "Trezor Hardware Wallet" }, { value: Wallet.WC, label: "WalletConnect" }, - { value: Wallet.XDEFI, label: "XDEFI" }, + { value: Wallet.CTRL, label: "Ctrl" }, { value: Wallet.EVM_EXTENSIONS, label: "Browser Extensions", diff --git a/packages/wallets/xdefi/CHANGELOG.md b/packages/wallets/ctrl/CHANGELOG.md similarity index 100% rename from packages/wallets/xdefi/CHANGELOG.md rename to packages/wallets/ctrl/CHANGELOG.md diff --git a/packages/wallets/xdefi/build.ts b/packages/wallets/ctrl/build.ts similarity index 100% rename from packages/wallets/xdefi/build.ts rename to packages/wallets/ctrl/build.ts diff --git a/packages/wallets/xdefi/package.json b/packages/wallets/ctrl/package.json similarity index 91% rename from packages/wallets/xdefi/package.json rename to packages/wallets/ctrl/package.json index 18e765e20..ba5b9055b 100644 --- a/packages/wallets/xdefi/package.json +++ b/packages/wallets/ctrl/package.json @@ -1,5 +1,5 @@ { - "description": "SwapKit Wallet - XDEFI", + "description": "SwapKit Wallet - Ctrl", "dependencies": { "@keplr-wallet/types": "0.12.110", "@swapkit/helpers": "workspace:*", @@ -15,7 +15,7 @@ "homepage": "https://github.com/thorswap/SwapKit", "license": "Apache-2.0", "main": "./dist/index.js", - "name": "@swapkit/wallet-xdefi", + "name": "@swapkit/wallet-ctrl", "repository": { "type": "git", "url": "git+https://github.com/thorswap/SwapKit.git" diff --git a/packages/wallets/xdefi/src/xdefiWallet.ts b/packages/wallets/ctrl/src/ctrlWallet.ts similarity index 86% rename from packages/wallets/xdefi/src/xdefiWallet.ts rename to packages/wallets/ctrl/src/ctrlWallet.ts index 2832d56d8..9e0767877 100644 --- a/packages/wallets/xdefi/src/xdefiWallet.ts +++ b/packages/wallets/ctrl/src/ctrlWallet.ts @@ -14,14 +14,14 @@ import type { ARBToolbox, AVAXToolbox, BSCToolbox } from "@swapkit/toolbox-evm"; import type { WalletTxParams } from "./walletHelpers"; import { - getXDEFIAddress, - getXDEFIProvider, - getXdefiMethods, + getCtrlAddress, + getCtrlMethods, + getCtrlProvider, solanaTransfer, walletTransfer, } from "./walletHelpers"; -export const XDEFI_SUPPORTED_CHAINS = [ +export const CTRL_SUPPORTED_CHAINS = [ Chain.Arbitrum, Chain.Avalanche, Chain.Base, @@ -45,7 +45,7 @@ async function getWalletMethodsForChain({ blockchairApiKey, covalentApiKey, ethplorerApiKey, -}: ConnectConfig & { chain: (typeof XDEFI_SUPPORTED_CHAINS)[number] }) { +}: ConnectConfig & { chain: (typeof CTRL_SUPPORTED_CHAINS)[number] }) { switch (chain) { case Chain.Solana: { const { SOLToolbox } = await import("@swapkit/toolbox-solana"); @@ -54,7 +54,7 @@ async function getWalletMethodsForChain({ const pubKey = await window.xfi?.solana?.connect(); if (!pubKey) { - throw new SwapKitError("wallet_xdefi_not_found"); + throw new SwapKitError("wallet_ctrl_not_found"); } return { ...toolbox, transfer: solanaTransfer(toolbox, pubKey.publicKey) }; @@ -128,17 +128,17 @@ async function getWalletMethodsForChain({ getBalance, BrowserProvider, } = await import("@swapkit/toolbox-evm"); - const ethereumWindowProvider = getXDEFIProvider(chain); + const ethereumWindowProvider = getCtrlProvider(chain); if (!ethereumWindowProvider) { - throw new SwapKitError("wallet_xdefi_not_found"); + throw new SwapKitError("wallet_ctrl_not_found"); } const apiKeys = ensureEVMApiKeys({ chain, covalentApiKey, ethplorerApiKey }); const provider = new BrowserProvider(ethereumWindowProvider, "any"); const signer = await provider.getSigner(); const toolbox = getToolboxByChain(chain)({ ...apiKeys, provider, signer }); - const xdefiMethods = getXdefiMethods(provider); + const ctrlMethods = getCtrlMethods(provider); try { chain !== Chain.Ethereum && @@ -155,7 +155,7 @@ async function getWalletMethodsForChain({ } catch (_error) { throw new SwapKitError({ errorKey: "wallet_failed_to_add_or_switch_network", - info: { wallet: WalletOption.XDEFI, chain }, + info: { wallet: WalletOption.CTRL, chain }, }); } @@ -170,8 +170,8 @@ async function getWalletMethodsForChain({ chainId: ChainToHexChainId[chain], toolbox: { ...toolbox, - ...xdefiMethods, - // Overwrite xdefi getBalance due to race condition in their app when connecting multiple evm wallets + ...ctrlMethods, + // Overwrite ctrl getBalance due to race condition in their app when connecting multiple evm wallets getBalance: (address: string, potentialScamFilter?: boolean) => getBalance({ chain, @@ -189,15 +189,15 @@ async function getWalletMethodsForChain({ } } -function connectXDEFI({ +function connectCtrl({ addChain, config: { covalentApiKey, ethplorerApiKey, blockchairApiKey, thorswapApiKey }, }: ConnectWalletParams) { - return async (chains: (typeof XDEFI_SUPPORTED_CHAINS)[number][]) => { + return async (chains: (typeof CTRL_SUPPORTED_CHAINS)[number][]) => { setRequestClientConfig({ apiKey: thorswapApiKey }); const promises = chains.map(async (chain) => { - const address = await getXDEFIAddress(chain); + const address = await getCtrlAddress(chain); const walletMethods = await getWalletMethodsForChain({ chain, blockchairApiKey, @@ -210,7 +210,7 @@ function connectXDEFI({ address, balance: [], chain, - walletType: WalletOption.XDEFI, + walletType: WalletOption.CTRL, }); }); @@ -220,4 +220,4 @@ function connectXDEFI({ }; } -export const xdefiWallet = { connectXDEFI } as const; +export const ctrlWallet = { connectCtrl } as const; diff --git a/packages/wallets/xdefi/src/index.ts b/packages/wallets/ctrl/src/index.ts similarity index 77% rename from packages/wallets/xdefi/src/index.ts rename to packages/wallets/ctrl/src/index.ts index 06d35d486..110848d3b 100644 --- a/packages/wallets/xdefi/src/index.ts +++ b/packages/wallets/ctrl/src/index.ts @@ -2,9 +2,9 @@ import type { Keplr } from "@keplr-wallet/types"; import type { Eip1193Provider } from "@swapkit/toolbox-evm"; import type { SolanaProvider } from "@swapkit/toolbox-solana"; -export { xdefiWallet, XDEFI_SUPPORTED_CHAINS } from "./xdefiWallet"; +export { ctrlWallet, CTRL_SUPPORTED_CHAINS } from "./ctrlWallet"; -type XdefiSolana = SolanaProvider & { isXDEFI: boolean }; +type CtrlSolana = SolanaProvider & { isXDEFI: boolean }; declare global { interface Window { @@ -18,7 +18,7 @@ declare global { litecoin: Eip1193Provider; thorchain: Eip1193Provider; mayachain: Eip1193Provider; - solana: XdefiSolana; + solana: CtrlSolana; }; } } diff --git a/packages/wallets/xdefi/src/walletHelpers.ts b/packages/wallets/ctrl/src/walletHelpers.ts similarity index 91% rename from packages/wallets/xdefi/src/walletHelpers.ts rename to packages/wallets/ctrl/src/walletHelpers.ts index 6047ad5d0..df48254d8 100644 --- a/packages/wallets/xdefi/src/walletHelpers.ts +++ b/packages/wallets/ctrl/src/walletHelpers.ts @@ -41,7 +41,7 @@ export type WalletTxParams = { gasLimit?: string | bigint | undefined; }; -export function getXDEFIProvider( +export function getCtrlProvider( chain: T, ): T extends Chain.Solana ? SolanaProvider @@ -50,7 +50,7 @@ export function getXDEFIProvider( : T extends EVMChain ? Eip1193Provider : undefined { - if (!window.xfi) throw new SwapKitError("wallet_xdefi_not_found"); + if (!window.xfi) throw new SwapKitError("wallet_ctrl_not_found"); switch (chain) { case Chain.Arbitrum: @@ -105,7 +105,7 @@ async function transaction({ params: TransactionParams[]; chain: Chain; }): Promise { - const client = getXDEFIProvider(chain); + const client = getCtrlProvider(chain); return new Promise((resolve, reject) => { if (client && "request" in client) { @@ -117,21 +117,21 @@ async function transaction({ }); } -export async function getXDEFIAddress(chain: Chain) { - const eipProvider = getXDEFIProvider(chain) as Eip1193Provider; +export async function getCtrlAddress(chain: Chain) { + const eipProvider = getCtrlProvider(chain) as Eip1193Provider; if (!eipProvider) { throw new SwapKitError({ errorKey: "wallet_provider_not_found", - info: { wallet: WalletOption.XDEFI, chain }, + info: { wallet: WalletOption.CTRL, chain }, }); } if ([Chain.Cosmos, Chain.Kujira].includes(chain)) { - const provider = getXDEFIProvider(Chain.Cosmos); + const provider = getCtrlProvider(Chain.Cosmos); if (!provider || "request" in provider) { throw new SwapKitError({ errorKey: "wallet_provider_not_found", - info: { wallet: WalletOption.XDEFI, chain }, + info: { wallet: WalletOption.CTRL, chain }, }); } @@ -154,7 +154,7 @@ export async function getXDEFIAddress(chain: Chain) { } if (chain === Chain.Solana) { - const provider = getXDEFIProvider(Chain.Solana); + const provider = getCtrlProvider(Chain.Solana); const accounts = await provider.connect(); return accounts.publicKey.toString(); @@ -174,7 +174,7 @@ export async function walletTransfer( method: TransactionMethod = "transfer", ) { if (!assetValue) { - throw new SwapKitError("wallet_xdefi_asset_not_defined"); + throw new SwapKitError("wallet_ctrl_asset_not_defined"); } /** @@ -182,7 +182,7 @@ export async function walletTransfer( * UTXO/Cosmos requires amount to be number */ - const from = await getXDEFIAddress(assetValue.chain); + const from = await getCtrlAddress(assetValue.chain); const params = [ { amount: { @@ -268,7 +268,7 @@ export function solanaTransfer( }; } -export function getXdefiMethods(provider: BrowserProvider) { +export function getCtrlMethods(provider: BrowserProvider) { return { call: async ({ contractAddress, @@ -279,7 +279,7 @@ export function getXdefiMethods(provider: BrowserProvider) { }: CallParams): Promise => { const contractProvider = provider; if (!contractAddress) { - throw new SwapKitError("wallet_xdefi_contract_address_not_provided"); + throw new SwapKitError("wallet_ctrl_contract_address_not_provided"); } const { createContract, createContractTxObject, isStateChangingCall, toHexString } = await import("@swapkit/toolbox-evm"); @@ -339,7 +339,7 @@ export function getXdefiMethods(provider: BrowserProvider) { sendTransaction: async (tx: EVMTxParams) => { const { from, to, data, value } = tx; if (!to) { - throw new SwapKitError("wallet_xdefi_send_transaction_no_address"); + throw new SwapKitError("wallet_ctrl_send_transaction_no_address"); } const { toHexString } = await import("@swapkit/toolbox-evm"); diff --git a/packages/wallets/xdefi/tsconfig.json b/packages/wallets/ctrl/tsconfig.json similarity index 100% rename from packages/wallets/xdefi/tsconfig.json rename to packages/wallets/ctrl/tsconfig.json diff --git a/playgrounds/nextjs/src/components/containers/NavigationBar.tsx b/playgrounds/nextjs/src/components/containers/NavigationBar.tsx index c401be4c4..78a641373 100644 --- a/playgrounds/nextjs/src/components/containers/NavigationBar.tsx +++ b/playgrounds/nextjs/src/components/containers/NavigationBar.tsx @@ -24,7 +24,7 @@ interface NavigationBarProps extends React.HTMLAttributes {} const AllChains = [...UTXOChains, ...EVMChains, ...CosmosChains]; const allowedChainsByWallet = { - [WalletOption.XDEFI]: AllChains.filter((chain) => ![Chain.Dash].includes(chain)), + [WalletOption.CTRL]: AllChains.filter((chain) => ![Chain.Dash].includes(chain)), [WalletOption.METAMASK]: EVMChains, [WalletOption.KEPLR]: CosmosChains, } as const; @@ -136,7 +136,7 @@ export function NavigationBar({ className, ...props }: NavigationBarProps) {
- {[WalletOption.XDEFI, WalletOption.METAMASK, WalletOption.KEPLR].map((option) => ( + {[WalletOption.CTRL, WalletOption.METAMASK, WalletOption.KEPLR].map((option) => (
{selectedChains.length && !checkWalletDisabled(option) ? (