@swapkit/core 1.0.0-rc.99 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/index.js +3 -0
  2. package/dist/index.js.map +12 -0
  3. package/package.json +23 -44
  4. package/src/__tests__/helpers.test.ts +65 -0
  5. package/src/client.ts +415 -0
  6. package/src/helpers/explorerUrls.ts +44 -0
  7. package/src/index.ts +6 -4
  8. package/src/types.ts +44 -0
  9. package/LICENSE +0 -201
  10. package/dist/index.cjs +0 -3
  11. package/dist/index.cjs.map +0 -1
  12. package/dist/index.d.ts +0 -230
  13. package/dist/index.es.js +0 -9119
  14. package/dist/index.es.js.map +0 -1
  15. package/src/aggregator/contracts/avaxGeneric.ts +0 -92
  16. package/src/aggregator/contracts/avaxWoofi.ts +0 -145
  17. package/src/aggregator/contracts/bscGeneric.ts +0 -106
  18. package/src/aggregator/contracts/ethGeneric.ts +0 -92
  19. package/src/aggregator/contracts/index.ts +0 -76
  20. package/src/aggregator/contracts/pancakeV2.ts +0 -145
  21. package/src/aggregator/contracts/pangolin.ts +0 -120
  22. package/src/aggregator/contracts/routers/index.ts +0 -58
  23. package/src/aggregator/contracts/routers/kyber.ts +0 -402
  24. package/src/aggregator/contracts/routers/oneinch.ts +0 -2188
  25. package/src/aggregator/contracts/routers/pancakeswap.ts +0 -340
  26. package/src/aggregator/contracts/routers/pangolin.ts +0 -340
  27. package/src/aggregator/contracts/routers/sushiswap.ts +0 -340
  28. package/src/aggregator/contracts/routers/traderJoe.ts +0 -340
  29. package/src/aggregator/contracts/routers/uniswapv2.ts +0 -340
  30. package/src/aggregator/contracts/routers/uniswapv3.ts +0 -254
  31. package/src/aggregator/contracts/routers/woofi.ts +0 -171
  32. package/src/aggregator/contracts/sushiswap.ts +0 -120
  33. package/src/aggregator/contracts/traderJoe.ts +0 -120
  34. package/src/aggregator/contracts/uniswapV2.ts +0 -120
  35. package/src/aggregator/contracts/uniswapV2Leg.ts +0 -128
  36. package/src/aggregator/contracts/uniswapV3_100.ts +0 -128
  37. package/src/aggregator/contracts/uniswapV3_10000.ts +0 -128
  38. package/src/aggregator/contracts/uniswapV3_3000.ts +0 -128
  39. package/src/aggregator/contracts/uniswapV3_500.ts +0 -128
  40. package/src/aggregator/getSwapParams.ts +0 -70
  41. package/src/client/__tests__/helpers.test.ts +0 -77
  42. package/src/client/explorerUrls.ts +0 -61
  43. package/src/client/index.ts +0 -769
  44. package/src/client/thornode.ts +0 -31
  45. package/src/client/types.ts +0 -115
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export*from"@swapkit/api";export*from"@swapkit/helpers";import{stripToCashAddress as zo} from"@swapkit/toolbox-utxo";import{lowercasedContractAbiMapping as H} from"@swapkit/contracts";import{ApproveMode as Y,AssetValue as Z,Chain as $,EVMChains as d,ProviderName as i,SwapKitError as P,isGasAsset as t} from"@swapkit/helpers";import{estimateTransactionFee as n,cosmosValidateAddress as s} from"@swapkit/toolbox-cosmos";import{evmValidateAddress as l} from"@swapkit/toolbox-evm";import{substrateValidateAddress as e} from"@swapkit/toolbox-substrate";import{utxoValidateAddress as a} from"@swapkit/toolbox-utxo";import{Chain as U,ChainToExplorerUrl as b,SwapKitError as c} from"@swapkit/helpers";function m({chain:q,txHash:_}){const y=b[q];switch(q){case U.Maya:case U.Kujira:case U.Cosmos:case U.THORChain:case U.Solana:return`${y}/tx/${_.startsWith("0x")?_.slice(2):_}`;case U.Arbitrum:case U.Avalanche:case U.BinanceSmartChain:case U.Ethereum:case U.Optimism:case U.Polkadot:case U.Polygon:return`${y}/tx/${_.startsWith("0x")?_:`0x${_}`}`;case U.Litecoin:case U.Bitcoin:case U.BitcoinCash:case U.Dogecoin:return`${y}/transaction/${_.toLowerCase()}`;default:throw new c({errorKey:"core_explorer_unsupported_chain",info:{chain:q}})}}function E({chain:q,address:_}){const y=b[q];switch(q){case U.Solana:return`${y}/account/${_}`;default:return`${y}/address/${_}`}}function Lo({apis:q={},config:_={},plugins:y,rpcUrls:C={},stagenet:D=!1,wallets:F}){const J={},Q=Object.entries(y).reduce((o,[x,{plugin:k,config:T}])=>{const B=k({wallets:J,stagenet:D,config:T??_});return o[x]=B,o},{}),M=Object.entries(F).reduce((o,[x,k])=>{const T=k({addChain:W,config:_,apis:q,rpcUrls:C});return o[x]=T,o},{});function S(o){const x=Q[o]||Object.values(Q)[0];if(!x)throw new P("core_plugin_not_found");return x}function O(o){const x=Object.values(Q).find((k)=>k.supportedSwapkitProviders?.includes(o));if(!x)throw new P("core_plugin_not_found");return x}function W(o){J[o.chain]=o}function j({assetValue:o,type:x="checkOnly",contractAddress:k}){const T=Q[k];if(T){if(x===Y.CheckOnly&&"isAssetValueApproved"in T)return T.isAssetValueApproved({assetValue:o});if(x===Y.Approve&&"approveAssetValue"in T)return T.approveAssetValue({assetValue:o});throw new P({errorKey:"core_approve_asset_target_invalid",info:{message:`Target ${String(k)} cannot be used for approve operation`}})}const B=o.chain,z=d.includes(B);if(z&&o.isGasAsset||!z||o.isSynthetic)return Promise.resolve(x==="checkOnly"?!0:"approved");const L=I(B),R=x==="checkOnly"?L.isApproved:L.approve;if(!R)throw new P("core_wallet_connection_not_found");if(!(o.address&&L.address&&typeof k==="string"))throw new P("core_approve_asset_address_or_from_not_found");return R({amount:o.getBaseValue("bigint"),assetAddress:o.address,from:L.address,spenderAddress:k})}function I(o){return J[o]}function v(){return{...J}}function N(o){return I(o)?.address||""}function K(o,x){return j({assetValue:o,contractAddress:x,type:Y.Approve})}function A(o,x){return j({assetValue:o,contractAddress:x,type:Y.CheckOnly})}function G(o){I(o)?.disconnect?.(),delete J[o]}function w(){for(let o of Object.keys(J))G(o)}function V(o,x){return x?f(o).then((k)=>k.balance):I(o)?.balance||[]}function r({address:o,chain:x}){switch(x){case $.Arbitrum:case $.Avalanche:case $.Optimism:case $.BinanceSmartChain:case $.Polygon:case $.Ethereum:return l({address:o});case $.Litecoin:case $.Dash:case $.Dogecoin:case $.BitcoinCash:case $.Bitcoin:return a({address:o,chain:x});case $.Cosmos:case $.Kujira:case $.Maya:case $.THORChain:return s({address:o,chain:x});case $.Polkadot:return e({address:o,chain:x});default:return!1}}async function f(o,x=!0){const k=[Z.from({chain:o})],T=I(o);if(!T)throw new P("core_wallet_connection_not_found");if("getBalance"in T){const B=await T.getBalance(T.address,x);T.balance=B?.length?B:k}return T}function h({route:o,pluginName:x,...k}){const T=x&&S(x)||O(o.providers[0]);if(!T)throw new P("core_swap_route_not_complete");if("swap"in T)return T.swap({...k,route:o});throw new P("core_plugin_swap_not_found")}function g({from:o,recipient:x,assetValue:k,feeOptionKey:T}){const B=k.chain,z=I(B);if(!z)throw new P("core_wallet_connection_not_found");return z.transfer({from:o,recipient:x,assetValue:k,feeOptionKey:T})}async function p({type:o,feeOptionKey:x,params:k}){const{assetValue:T}=k,{chain:B}=T;if(!I(B))throw new P("core_wallet_connection_not_found");const z=Z.from({chain:B});switch(B){case $.Arbitrum:case $.Avalanche:case $.Ethereum:case $.BinanceSmartChain:case $.Polygon:{const X=I(B);if(o==="transfer"){const L=await X.createTransferTx(k);return X.estimateTransactionFee(L,x)}if(o==="approve"&&!t(T))return X.estimateTransactionFee(await X.createApprovalTx({assetAddress:T.address,spenderAddress:k.contractAddress,amount:T.getBaseValue("bigint"),from:X.address}),x);if(o==="swap"){if(k.route.providers[0]===i.CHAINFLIP){const u=await X.createTransferTx({from:X.address,recipient:X.address,assetValue:T});return X.estimateTransactionFee(u,x)}const{evmTransactionDetails:R}=k.route;if(!(R&&H[R.contractAddress]))return;return X.estimateTransactionFee(await X.createContractTxObject({contractAddress:R.contractAddress,abi:H[R.contractAddress],funcName:R.contractMethod,funcParams:R.contractParams}),x)}return Z.from({chain:B})}case $.Bitcoin:case $.BitcoinCash:case $.Dogecoin:case $.Dash:case $.Litecoin:{const{estimateMaxSendableAmount:X,address:L}=I(B);return X({...k,feeOptionKey:x,from:L,recipient:L})}case $.THORChain:case $.Maya:case $.Kujira:case $.Cosmos:return n(k);case $.Polkadot:{const{address:X,estimateTransactionFee:L}=I(B);return L({...k,recipient:X})}default:return z}}return{...Q,...M,approveAssetValue:K,getAddress:N,getBalance:V,getExplorerAddressUrl:E,getExplorerTxUrl:m,getWallet:I,getAllWallets:v,getWalletWithBalance:f,isAssetValueApproved:A,estimateTransactionFee:p,swap:h,transfer:g,validateAddress:r,disconnectAll:w,disconnectChain:G}}export{zo as stripToCashAddress,Lo as SwapKit};
2
+
3
+ //# debugId=C19E100412E60E5664756E2164756E21
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/client.ts", "../src/helpers/explorerUrls.ts"],
4
+ "sourcesContent": [
5
+ "export * from \"@swapkit/api\";\nexport * from \"@swapkit/helpers\";\nexport { stripToCashAddress } from \"@swapkit/toolbox-utxo\";\n\nexport * from \"./client.ts\";\nexport * from \"./types.ts\";\n",
6
+ "import { lowercasedContractAbiMapping } from \"@swapkit/contracts\";\nimport {\n type AddChainWalletParams,\n ApproveMode,\n type ApproveReturnType,\n AssetValue,\n Chain,\n type ConnectConfig,\n type EVMChain,\n EVMChains,\n type FeeOption,\n ProviderName as PluginNameEnum,\n SwapKitError,\n type SwapParams,\n type WalletChain,\n isGasAsset,\n} from \"@swapkit/helpers\";\nimport {\n type TransferParams as CosmosTransferParams,\n estimateTransactionFee as cosmosTransactionFee,\n cosmosValidateAddress,\n} from \"@swapkit/toolbox-cosmos\";\nimport { type TransferParams as EVMTransferParams, evmValidateAddress } from \"@swapkit/toolbox-evm\";\nimport { substrateValidateAddress } from \"@swapkit/toolbox-substrate\";\nimport { type UTXOTransferParams, utxoValidateAddress } from \"@swapkit/toolbox-utxo\";\n\nimport {\n getExplorerAddressUrl as getAddressUrl,\n getExplorerTxUrl as getTxUrl,\n} from \"./helpers/explorerUrls.ts\";\nimport type { Apis, SwapKitPluginInterface, SwapKitWallet, Wallet } from \"./types.ts\";\n\nexport function SwapKit<\n Plugins extends { [key in string]: SwapKitPluginInterface<{ [key in string]: Todo }> },\n Wallets extends { [key in string]: SwapKitWallet<NotWorth[]> },\n>({\n apis = {},\n config = {},\n plugins,\n rpcUrls = {},\n stagenet = false,\n wallets,\n}: {\n apis?: Apis;\n config?: ConnectConfig;\n plugins: Plugins;\n rpcUrls?: { [key in Chain]?: string };\n stagenet?: boolean;\n wallets: Wallets;\n}) {\n type PluginName = keyof Plugins;\n\n const connectedWallets = {} as Wallet;\n const availablePlugins = Object.entries(plugins).reduce(\n (acc, [pluginName, { plugin, config: pluginConfig }]) => {\n const methods = plugin({\n wallets: connectedWallets,\n stagenet,\n config: pluginConfig ?? config,\n });\n\n // @ts-expect-error\n acc[pluginName] = methods;\n return acc;\n },\n {} as { [key in PluginName]: ReturnType<Plugins[key][\"plugin\"]> },\n );\n\n const connectWalletMethods = Object.entries(wallets).reduce(\n (acc, [walletName, wallet]) => {\n const connectWallet = wallet({ addChain, config, apis, rpcUrls });\n\n // @ts-expect-error\n acc[walletName] = connectWallet;\n return acc;\n },\n {} as { [key in keyof Wallets]: ReturnType<Wallets[key]> },\n );\n\n function getSwapKitPlugin<T extends PluginName>(pluginName: T) {\n const plugin = availablePlugins[pluginName] || Object.values(availablePlugins)[0];\n\n if (!plugin) {\n throw new SwapKitError(\"core_plugin_not_found\");\n }\n\n return plugin;\n }\n\n function getSwapKitPluginForSKProvider(pluginName: PluginNameEnum): Plugins[keyof Plugins] {\n const plugin = Object.values(availablePlugins).find((plugin) =>\n plugin.supportedSwapkitProviders?.includes(pluginName),\n );\n\n if (!plugin) {\n throw new SwapKitError(\"core_plugin_not_found\");\n }\n\n return plugin;\n }\n\n function addChain<T extends Chain>(connectWallet: AddChainWalletParams<T>) {\n // @ts-expect-error: TODO\n connectedWallets[connectWallet.chain] = connectWallet;\n }\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>\n function approve<T extends ApproveMode>({\n assetValue,\n type = \"checkOnly\" as T,\n contractAddress: spenderAddress,\n }: {\n type: T;\n assetValue: AssetValue;\n contractAddress: string | PluginName;\n }) {\n const plugin = availablePlugins[spenderAddress];\n\n if (plugin) {\n if (type === ApproveMode.CheckOnly && \"isAssetValueApproved\" in plugin) {\n return plugin.isAssetValueApproved({ assetValue }) as ApproveReturnType<T>;\n }\n if (type === ApproveMode.Approve && \"approveAssetValue\" in plugin) {\n return plugin.approveAssetValue({ assetValue }) as ApproveReturnType<T>;\n }\n\n throw new SwapKitError({\n errorKey: \"core_approve_asset_target_invalid\",\n info: { message: `Target ${String(spenderAddress)} cannot be used for approve operation` },\n });\n }\n\n const chain = assetValue.chain as EVMChain;\n const isEVMChain = EVMChains.includes(chain);\n const isNativeEVM = isEVMChain && assetValue.isGasAsset;\n\n if (isNativeEVM || !isEVMChain || assetValue.isSynthetic) {\n return Promise.resolve(type === \"checkOnly\" ? true : \"approved\") as ApproveReturnType<T>;\n }\n\n const wallet = getWallet(chain);\n const walletAction = type === \"checkOnly\" ? wallet.isApproved : wallet.approve;\n if (!walletAction) throw new SwapKitError(\"core_wallet_connection_not_found\");\n\n if (!(assetValue.address && wallet.address && typeof spenderAddress === \"string\")) {\n throw new SwapKitError(\"core_approve_asset_address_or_from_not_found\");\n }\n\n return walletAction({\n amount: assetValue.getBaseValue(\"bigint\"),\n assetAddress: assetValue.address,\n from: wallet.address,\n spenderAddress,\n }) as ApproveReturnType<T>;\n }\n\n /**\n * @Public\n */\n function getWallet<T extends Chain>(chain: T) {\n return connectedWallets[chain];\n }\n\n function getAllWallets() {\n return { ...connectedWallets };\n }\n\n function getAddress<T extends Chain>(chain: T) {\n return getWallet(chain)?.address || \"\";\n }\n\n function approveAssetValue(assetValue: AssetValue, contractAddress: string | PluginName) {\n return approve({ assetValue, contractAddress, type: ApproveMode.Approve });\n }\n\n function isAssetValueApproved(assetValue: AssetValue, contractAddress: string | PluginName) {\n return approve({ assetValue, contractAddress, type: ApproveMode.CheckOnly });\n }\n\n function disconnectChain<T extends Chain>(chain: T) {\n const wallet = getWallet(chain);\n wallet?.disconnect?.();\n delete connectedWallets[chain];\n }\n\n function disconnectAll() {\n for (const chain of Object.keys(connectedWallets) as (keyof typeof connectedWallets)[]) {\n disconnectChain(chain);\n }\n }\n\n function getBalance<T extends Chain>(chain: T, refresh?: boolean) {\n return refresh\n ? getWalletWithBalance(chain).then((wallet) => wallet.balance)\n : getWallet(chain)?.balance || [];\n }\n\n function validateAddress({ address, chain }: { address: string; chain: Chain }) {\n switch (chain) {\n case Chain.Arbitrum:\n case Chain.Avalanche:\n case Chain.Optimism:\n case Chain.BinanceSmartChain:\n case Chain.Polygon:\n case Chain.Ethereum:\n return evmValidateAddress({ address });\n\n case Chain.Litecoin:\n case Chain.Dash:\n case Chain.Dogecoin:\n case Chain.BitcoinCash:\n case Chain.Bitcoin:\n return utxoValidateAddress({ address, chain });\n\n case Chain.Cosmos:\n case Chain.Kujira:\n case Chain.Maya:\n case Chain.THORChain:\n return cosmosValidateAddress({ address, chain });\n\n case Chain.Polkadot:\n return substrateValidateAddress({ address, chain });\n\n default:\n return false;\n }\n }\n\n async function getWalletWithBalance<T extends Chain>(chain: T, potentialScamFilter = true) {\n const defaultBalance = [AssetValue.from({ chain })];\n const wallet = getWallet(chain);\n\n if (!wallet) {\n throw new SwapKitError(\"core_wallet_connection_not_found\");\n }\n\n if (\"getBalance\" in wallet) {\n // @ts-expect-error TODO add getBalance to radix\n const balance = await wallet.getBalance(wallet.address, potentialScamFilter);\n wallet.balance = balance?.length ? balance : defaultBalance;\n }\n\n return wallet;\n }\n\n function swap<T extends PluginName>({ route, pluginName, ...rest }: SwapParams<T>) {\n const plugin =\n (pluginName && getSwapKitPlugin(pluginName)) ||\n getSwapKitPluginForSKProvider(route.providers[0] as PluginNameEnum);\n\n if (!plugin) throw new SwapKitError(\"core_swap_route_not_complete\");\n\n if (\"swap\" in plugin) {\n return plugin.swap({ ...rest, route });\n }\n\n throw new SwapKitError(\"core_plugin_swap_not_found\");\n }\n\n function transfer({\n from,\n recipient,\n assetValue,\n feeOptionKey,\n }: UTXOTransferParams | EVMTransferParams | CosmosTransferParams) {\n const chain = assetValue.chain as WalletChain;\n const wallet = getWallet(chain);\n if (!wallet) throw new SwapKitError(\"core_wallet_connection_not_found\");\n\n return wallet.transfer({ from, recipient, assetValue, feeOptionKey });\n }\n\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: TODO clean this up\n async function estimateTransactionFee<T extends PluginName>({\n type,\n feeOptionKey,\n params,\n }: (\n | { type: \"swap\"; params: SwapParams<T> & { assetValue: AssetValue } }\n | {\n type: \"transfer\";\n params: UTXOTransferParams | EVMTransferParams | CosmosTransferParams;\n }\n | {\n type: \"approve\";\n params: {\n assetValue: AssetValue;\n contractAddress: string | PluginName;\n feeOptionKey?: FeeOption;\n };\n }\n ) & {\n feeOptionKey: FeeOption;\n }): Promise<AssetValue | undefined> {\n const { assetValue } = params;\n const { chain } = assetValue;\n\n if (!getWallet(chain)) throw new SwapKitError(\"core_wallet_connection_not_found\");\n\n const baseValue = AssetValue.from({ chain });\n\n switch (chain) {\n case Chain.Arbitrum:\n case Chain.Avalanche:\n case Chain.Ethereum:\n case Chain.BinanceSmartChain:\n case Chain.Polygon: {\n const wallet = getWallet(chain);\n if (type === \"transfer\") {\n const txObject = await wallet.createTransferTx(params);\n return wallet.estimateTransactionFee(txObject, feeOptionKey);\n }\n\n if (type === \"approve\" && !isGasAsset(assetValue)) {\n return wallet.estimateTransactionFee(\n await wallet.createApprovalTx({\n assetAddress: assetValue.address as string,\n spenderAddress: params.contractAddress as string,\n amount: assetValue.getBaseValue(\"bigint\"),\n from: wallet.address,\n }),\n feeOptionKey,\n );\n }\n\n if (type === \"swap\") {\n const plugin = params.route.providers[0] as PluginNameEnum;\n if (plugin === PluginNameEnum.CHAINFLIP) {\n const txObject = await wallet.createTransferTx({\n from: wallet.address,\n recipient: wallet.address,\n assetValue,\n });\n return wallet.estimateTransactionFee(txObject, feeOptionKey);\n }\n\n const { evmTransactionDetails } = params.route;\n if (\n !(\n evmTransactionDetails &&\n lowercasedContractAbiMapping[evmTransactionDetails.contractAddress]\n )\n ) {\n return undefined;\n }\n\n return wallet.estimateTransactionFee(\n await wallet.createContractTxObject({\n contractAddress: evmTransactionDetails.contractAddress,\n // biome-ignore lint/style/noNonNullAssertion: TS cant infer the type\n abi: lowercasedContractAbiMapping[evmTransactionDetails.contractAddress]!,\n funcName: evmTransactionDetails.contractMethod,\n funcParams: evmTransactionDetails.contractParams,\n }),\n feeOptionKey,\n );\n }\n\n return AssetValue.from({ chain });\n }\n\n case Chain.Bitcoin:\n case Chain.BitcoinCash:\n case Chain.Dogecoin:\n case Chain.Dash:\n case Chain.Litecoin: {\n const { estimateMaxSendableAmount, address } = getWallet(chain);\n\n return estimateMaxSendableAmount({\n ...params,\n feeOptionKey,\n from: address,\n recipient: address,\n });\n }\n\n case Chain.THORChain:\n case Chain.Maya:\n case Chain.Kujira:\n case Chain.Cosmos: {\n return cosmosTransactionFee(params);\n }\n\n case Chain.Polkadot: {\n const { address, estimateTransactionFee } = getWallet(chain);\n\n return estimateTransactionFee({ ...params, recipient: address });\n }\n\n default:\n return baseValue;\n }\n }\n\n return {\n ...availablePlugins,\n ...connectWalletMethods,\n\n approveAssetValue,\n getAddress,\n getBalance,\n getExplorerAddressUrl: getAddressUrl,\n getExplorerTxUrl: getTxUrl,\n getWallet,\n getAllWallets,\n getWalletWithBalance,\n isAssetValueApproved,\n estimateTransactionFee,\n swap,\n transfer,\n validateAddress,\n disconnectAll,\n disconnectChain,\n };\n}\n",
7
+ "import { Chain, ChainToExplorerUrl, SwapKitError } from \"@swapkit/helpers\";\n\nexport function getExplorerTxUrl({ chain, txHash }: { txHash: string; chain: Chain }) {\n const baseUrl = ChainToExplorerUrl[chain];\n\n switch (chain) {\n case Chain.Maya:\n case Chain.Kujira:\n case Chain.Cosmos:\n case Chain.THORChain:\n case Chain.Solana:\n return `${baseUrl}/tx/${txHash.startsWith(\"0x\") ? txHash.slice(2) : txHash}`;\n\n case Chain.Arbitrum:\n case Chain.Avalanche:\n case Chain.BinanceSmartChain:\n case Chain.Ethereum:\n case Chain.Optimism:\n case Chain.Polkadot:\n case Chain.Polygon:\n return `${baseUrl}/tx/${txHash.startsWith(\"0x\") ? txHash : `0x${txHash}`}`;\n\n case Chain.Litecoin:\n case Chain.Bitcoin:\n case Chain.BitcoinCash:\n case Chain.Dogecoin:\n return `${baseUrl}/transaction/${txHash.toLowerCase()}`;\n\n default:\n throw new SwapKitError({ errorKey: \"core_explorer_unsupported_chain\", info: { chain } });\n }\n}\n\nexport function getExplorerAddressUrl({ chain, address }: { address: string; chain: Chain }) {\n const baseUrl = ChainToExplorerUrl[chain];\n\n switch (chain) {\n case Chain.Solana:\n return `${baseUrl}/account/${address}`;\n\n default:\n return `${baseUrl}/address/${address}`;\n }\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "C19E100412E60E5664756E2164756E21",
11
+ "names": []
12
+ }
package/package.json CHANGED
@@ -1,60 +1,39 @@
1
1
  {
2
- "author": "swapkit-oss-team",
2
+ "author": "swapkit-oss",
3
3
  "dependencies": {
4
- "@swapkit/helpers": "1.0.0-rc.71",
5
- "@swapkit/types": "1.0.0-rc.37"
6
- },
7
- "description": "SwapKit Lib core",
8
- "devDependencies": {
9
- "@vitest/coverage-istanbul": "1.2.1",
10
- "vite": "5.0.12",
11
- "vitest": "1.2.1",
12
- "@internal/config": "0.0.2-rc.0",
13
- "@swapkit/tokens": "1.0.0-rc.34",
14
- "@swapkit/toolbox-cosmos": "1.0.0-rc.82",
15
- "@swapkit/toolbox-evm": "1.0.0-rc.77",
16
- "@swapkit/toolbox-substrate": "1.0.0-rc.5",
17
- "@swapkit/toolbox-utxo": "1.0.0-rc.76"
18
- },
19
- "peerDependencies": {
20
- "@swapkit/tokens": "1.0.0-rc.34",
21
- "@swapkit/toolbox-cosmos": "1.0.0-rc.82",
22
- "@swapkit/toolbox-evm": "1.0.0-rc.77",
23
- "@swapkit/toolbox-substrate": "1.0.0-rc.5",
24
- "@swapkit/toolbox-utxo": "1.0.0-rc.76"
25
- },
26
- "eslintConfig": {
27
- "extends": "../../../internal/eslint-config"
28
- },
29
- "exports": {
30
- ".": {
31
- "import": "./dist/index.es.js",
32
- "require": "./dist/index.cjs",
33
- "types": "./dist/index.d.ts"
34
- }
4
+ "@swapkit/api": "1.0.1",
5
+ "@swapkit/contracts": "1.0.1",
6
+ "@swapkit/helpers": "1.0.1",
7
+ "@swapkit/plugin-evm": "1.0.1",
8
+ "@swapkit/toolbox-cosmos": "1.0.1",
9
+ "@swapkit/toolbox-evm": "1.0.1",
10
+ "@swapkit/toolbox-solana": "1.0.1",
11
+ "@swapkit/toolbox-substrate": "1.0.1",
12
+ "@swapkit/toolbox-utxo": "1.0.1"
35
13
  },
14
+ "description": "SwapKit - Core",
36
15
  "files": [
37
16
  "src/",
38
17
  "dist/"
39
18
  ],
40
19
  "homepage": "https://github.com/thorswap/SwapKit",
41
20
  "license": "Apache-2.0",
42
- "main": "./dist/index.cjs",
43
- "module": "./dist/index.es.js",
21
+ "main": "./dist/index.js",
44
22
  "name": "@swapkit/core",
45
23
  "react-native": "./src/index.ts",
46
24
  "repository": {
47
25
  "type": "git",
48
26
  "url": "git+https://github.com/thorswap/SwapKit.git"
49
27
  },
50
- "type": "module",
51
- "types": "./dist/index.d.ts",
52
- "version": "1.0.0-rc.99",
53
28
  "scripts": {
54
- "build": "NODE_OPTIONS=--max_old_space_size=16384 vite build",
55
- "clean": "rm -rf dist vite.config.ts.* .turbo node_modules",
56
- "lint": "eslint ./ --ext .ts,.tsx --fix; tsc --noEmit",
57
- "test": "vitest --run",
58
- "test:coverage": "vitest run --coverage"
59
- }
60
- }
29
+ "build": "bun run ./build.ts",
30
+ "clean": "rm -rf dist node_modules *.tsbuildinfo",
31
+ "lint": "biome check --write ./src",
32
+ "test": "echo 'bun test'",
33
+ "test:coverage": "bun test --coverage",
34
+ "type-check": "tsc --noEmit"
35
+ },
36
+ "type": "module",
37
+ "types": "./src/index.ts",
38
+ "version": "1.0.1"
39
+ }
@@ -0,0 +1,65 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Chain, ChainToExplorerUrl, CosmosChains, EVMChains, UTXOChains } from "@swapkit/helpers";
3
+ import { getExplorerAddressUrl, getExplorerTxUrl } from "../helpers/explorerUrls.ts";
4
+
5
+ describe("Explorer URLs", () => {
6
+ describe("CosmosChains", () => {
7
+ for (const chain of CosmosChains) {
8
+ test(`getExplorerTxUrl returns correct URL for ${chain}`, () => {
9
+ expect(getExplorerTxUrl({ chain, txHash: "0x123456789" })).toBe(
10
+ `${ChainToExplorerUrl[chain]}/tx/123456789`,
11
+ );
12
+
13
+ expect(getExplorerAddressUrl({ chain, address: "asdfg" })).toBe(
14
+ `${ChainToExplorerUrl[chain]}/address/asdfg`,
15
+ );
16
+ });
17
+ }
18
+ });
19
+
20
+ describe("EVMChains & SubstrateChains", () => {
21
+ for (const chain of [...EVMChains, Chain.Polkadot]) {
22
+ test(`getExplorerTxUrl returns correct URL for ${chain}`, () => {
23
+ expect(getExplorerTxUrl({ chain, txHash: "0x123456789" })).toBe(
24
+ `${ChainToExplorerUrl[chain]}/tx/0x123456789`,
25
+ );
26
+
27
+ expect(getExplorerAddressUrl({ chain, address: "asdfg" })).toBe(
28
+ `${ChainToExplorerUrl[chain]}/address/asdfg`,
29
+ );
30
+ });
31
+ }
32
+
33
+ test("getExplorerTxUrl adds 0x for EVM like chains", () => {
34
+ expect(getExplorerTxUrl({ chain: Chain.Ethereum, txHash: "12345" })).toBe(
35
+ "https://etherscan.io/tx/0x12345",
36
+ );
37
+ });
38
+ });
39
+
40
+ describe("UTXOChains", () => {
41
+ for (const chain of UTXOChains.filter((c) => c !== Chain.Dash)) {
42
+ test(`getExplorerTxUrl returns correct URL for ${chain}`, () => {
43
+ expect(getExplorerTxUrl({ chain, txHash: "0x123456789" })).toBe(
44
+ `${ChainToExplorerUrl[chain]}/transaction/0x123456789`,
45
+ );
46
+
47
+ expect(getExplorerAddressUrl({ chain, address: "asdfg" })).toBe(
48
+ `${ChainToExplorerUrl[chain]}/address/asdfg`,
49
+ );
50
+ });
51
+ }
52
+ });
53
+
54
+ describe("Solana", () => {
55
+ test("getExplorerTxUrl returns correct URL for Solana", () => {
56
+ expect(getExplorerTxUrl({ chain: Chain.Solana, txHash: "b123456789" })).toBe(
57
+ "https://solscan.io/tx/b123456789",
58
+ );
59
+
60
+ expect(getExplorerAddressUrl({ chain: Chain.Solana, address: "asdfg" })).toBe(
61
+ "https://solscan.io/account/asdfg",
62
+ );
63
+ });
64
+ });
65
+ });
package/src/client.ts ADDED
@@ -0,0 +1,415 @@
1
+ import { lowercasedContractAbiMapping } from "@swapkit/contracts";
2
+ import {
3
+ type AddChainWalletParams,
4
+ ApproveMode,
5
+ type ApproveReturnType,
6
+ AssetValue,
7
+ Chain,
8
+ type ConnectConfig,
9
+ type EVMChain,
10
+ EVMChains,
11
+ type FeeOption,
12
+ ProviderName as PluginNameEnum,
13
+ SwapKitError,
14
+ type SwapParams,
15
+ type WalletChain,
16
+ isGasAsset,
17
+ } from "@swapkit/helpers";
18
+ import {
19
+ type TransferParams as CosmosTransferParams,
20
+ estimateTransactionFee as cosmosTransactionFee,
21
+ cosmosValidateAddress,
22
+ } from "@swapkit/toolbox-cosmos";
23
+ import { type TransferParams as EVMTransferParams, evmValidateAddress } from "@swapkit/toolbox-evm";
24
+ import { substrateValidateAddress } from "@swapkit/toolbox-substrate";
25
+ import { type UTXOTransferParams, utxoValidateAddress } from "@swapkit/toolbox-utxo";
26
+
27
+ import {
28
+ getExplorerAddressUrl as getAddressUrl,
29
+ getExplorerTxUrl as getTxUrl,
30
+ } from "./helpers/explorerUrls.ts";
31
+ import type { Apis, SwapKitPluginInterface, SwapKitWallet, Wallet } from "./types.ts";
32
+
33
+ export function SwapKit<
34
+ Plugins extends { [key in string]: SwapKitPluginInterface<{ [key in string]: Todo }> },
35
+ Wallets extends { [key in string]: SwapKitWallet<NotWorth[]> },
36
+ >({
37
+ apis = {},
38
+ config = {},
39
+ plugins,
40
+ rpcUrls = {},
41
+ stagenet = false,
42
+ wallets,
43
+ }: {
44
+ apis?: Apis;
45
+ config?: ConnectConfig;
46
+ plugins: Plugins;
47
+ rpcUrls?: { [key in Chain]?: string };
48
+ stagenet?: boolean;
49
+ wallets: Wallets;
50
+ }) {
51
+ type PluginName = keyof Plugins;
52
+
53
+ const connectedWallets = {} as Wallet;
54
+ const availablePlugins = Object.entries(plugins).reduce(
55
+ (acc, [pluginName, { plugin, config: pluginConfig }]) => {
56
+ const methods = plugin({
57
+ wallets: connectedWallets,
58
+ stagenet,
59
+ config: pluginConfig ?? config,
60
+ });
61
+
62
+ // @ts-expect-error
63
+ acc[pluginName] = methods;
64
+ return acc;
65
+ },
66
+ {} as { [key in PluginName]: ReturnType<Plugins[key]["plugin"]> },
67
+ );
68
+
69
+ const connectWalletMethods = Object.entries(wallets).reduce(
70
+ (acc, [walletName, wallet]) => {
71
+ const connectWallet = wallet({ addChain, config, apis, rpcUrls });
72
+
73
+ // @ts-expect-error
74
+ acc[walletName] = connectWallet;
75
+ return acc;
76
+ },
77
+ {} as { [key in keyof Wallets]: ReturnType<Wallets[key]> },
78
+ );
79
+
80
+ function getSwapKitPlugin<T extends PluginName>(pluginName: T) {
81
+ const plugin = availablePlugins[pluginName] || Object.values(availablePlugins)[0];
82
+
83
+ if (!plugin) {
84
+ throw new SwapKitError("core_plugin_not_found");
85
+ }
86
+
87
+ return plugin;
88
+ }
89
+
90
+ function getSwapKitPluginForSKProvider(pluginName: PluginNameEnum): Plugins[keyof Plugins] {
91
+ const plugin = Object.values(availablePlugins).find((plugin) =>
92
+ plugin.supportedSwapkitProviders?.includes(pluginName),
93
+ );
94
+
95
+ if (!plugin) {
96
+ throw new SwapKitError("core_plugin_not_found");
97
+ }
98
+
99
+ return plugin;
100
+ }
101
+
102
+ function addChain<T extends Chain>(connectWallet: AddChainWalletParams<T>) {
103
+ // @ts-expect-error: TODO
104
+ connectedWallets[connectWallet.chain] = connectWallet;
105
+ }
106
+
107
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: <explanation>
108
+ function approve<T extends ApproveMode>({
109
+ assetValue,
110
+ type = "checkOnly" as T,
111
+ contractAddress: spenderAddress,
112
+ }: {
113
+ type: T;
114
+ assetValue: AssetValue;
115
+ contractAddress: string | PluginName;
116
+ }) {
117
+ const plugin = availablePlugins[spenderAddress];
118
+
119
+ if (plugin) {
120
+ if (type === ApproveMode.CheckOnly && "isAssetValueApproved" in plugin) {
121
+ return plugin.isAssetValueApproved({ assetValue }) as ApproveReturnType<T>;
122
+ }
123
+ if (type === ApproveMode.Approve && "approveAssetValue" in plugin) {
124
+ return plugin.approveAssetValue({ assetValue }) as ApproveReturnType<T>;
125
+ }
126
+
127
+ throw new SwapKitError({
128
+ errorKey: "core_approve_asset_target_invalid",
129
+ info: { message: `Target ${String(spenderAddress)} cannot be used for approve operation` },
130
+ });
131
+ }
132
+
133
+ const chain = assetValue.chain as EVMChain;
134
+ const isEVMChain = EVMChains.includes(chain);
135
+ const isNativeEVM = isEVMChain && assetValue.isGasAsset;
136
+
137
+ if (isNativeEVM || !isEVMChain || assetValue.isSynthetic) {
138
+ return Promise.resolve(type === "checkOnly" ? true : "approved") as ApproveReturnType<T>;
139
+ }
140
+
141
+ const wallet = getWallet(chain);
142
+ const walletAction = type === "checkOnly" ? wallet.isApproved : wallet.approve;
143
+ if (!walletAction) throw new SwapKitError("core_wallet_connection_not_found");
144
+
145
+ if (!(assetValue.address && wallet.address && typeof spenderAddress === "string")) {
146
+ throw new SwapKitError("core_approve_asset_address_or_from_not_found");
147
+ }
148
+
149
+ return walletAction({
150
+ amount: assetValue.getBaseValue("bigint"),
151
+ assetAddress: assetValue.address,
152
+ from: wallet.address,
153
+ spenderAddress,
154
+ }) as ApproveReturnType<T>;
155
+ }
156
+
157
+ /**
158
+ * @Public
159
+ */
160
+ function getWallet<T extends Chain>(chain: T) {
161
+ return connectedWallets[chain];
162
+ }
163
+
164
+ function getAllWallets() {
165
+ return { ...connectedWallets };
166
+ }
167
+
168
+ function getAddress<T extends Chain>(chain: T) {
169
+ return getWallet(chain)?.address || "";
170
+ }
171
+
172
+ function approveAssetValue(assetValue: AssetValue, contractAddress: string | PluginName) {
173
+ return approve({ assetValue, contractAddress, type: ApproveMode.Approve });
174
+ }
175
+
176
+ function isAssetValueApproved(assetValue: AssetValue, contractAddress: string | PluginName) {
177
+ return approve({ assetValue, contractAddress, type: ApproveMode.CheckOnly });
178
+ }
179
+
180
+ function disconnectChain<T extends Chain>(chain: T) {
181
+ const wallet = getWallet(chain);
182
+ wallet?.disconnect?.();
183
+ delete connectedWallets[chain];
184
+ }
185
+
186
+ function disconnectAll() {
187
+ for (const chain of Object.keys(connectedWallets) as (keyof typeof connectedWallets)[]) {
188
+ disconnectChain(chain);
189
+ }
190
+ }
191
+
192
+ function getBalance<T extends Chain>(chain: T, refresh?: boolean) {
193
+ return refresh
194
+ ? getWalletWithBalance(chain).then((wallet) => wallet.balance)
195
+ : getWallet(chain)?.balance || [];
196
+ }
197
+
198
+ function validateAddress({ address, chain }: { address: string; chain: Chain }) {
199
+ switch (chain) {
200
+ case Chain.Arbitrum:
201
+ case Chain.Avalanche:
202
+ case Chain.Optimism:
203
+ case Chain.BinanceSmartChain:
204
+ case Chain.Polygon:
205
+ case Chain.Ethereum:
206
+ return evmValidateAddress({ address });
207
+
208
+ case Chain.Litecoin:
209
+ case Chain.Dash:
210
+ case Chain.Dogecoin:
211
+ case Chain.BitcoinCash:
212
+ case Chain.Bitcoin:
213
+ return utxoValidateAddress({ address, chain });
214
+
215
+ case Chain.Cosmos:
216
+ case Chain.Kujira:
217
+ case Chain.Maya:
218
+ case Chain.THORChain:
219
+ return cosmosValidateAddress({ address, chain });
220
+
221
+ case Chain.Polkadot:
222
+ return substrateValidateAddress({ address, chain });
223
+
224
+ default:
225
+ return false;
226
+ }
227
+ }
228
+
229
+ async function getWalletWithBalance<T extends Chain>(chain: T, potentialScamFilter = true) {
230
+ const defaultBalance = [AssetValue.from({ chain })];
231
+ const wallet = getWallet(chain);
232
+
233
+ if (!wallet) {
234
+ throw new SwapKitError("core_wallet_connection_not_found");
235
+ }
236
+
237
+ if ("getBalance" in wallet) {
238
+ // @ts-expect-error TODO add getBalance to radix
239
+ const balance = await wallet.getBalance(wallet.address, potentialScamFilter);
240
+ wallet.balance = balance?.length ? balance : defaultBalance;
241
+ }
242
+
243
+ return wallet;
244
+ }
245
+
246
+ function swap<T extends PluginName>({ route, pluginName, ...rest }: SwapParams<T>) {
247
+ const plugin =
248
+ (pluginName && getSwapKitPlugin(pluginName)) ||
249
+ getSwapKitPluginForSKProvider(route.providers[0] as PluginNameEnum);
250
+
251
+ if (!plugin) throw new SwapKitError("core_swap_route_not_complete");
252
+
253
+ if ("swap" in plugin) {
254
+ return plugin.swap({ ...rest, route });
255
+ }
256
+
257
+ throw new SwapKitError("core_plugin_swap_not_found");
258
+ }
259
+
260
+ function transfer({
261
+ from,
262
+ recipient,
263
+ assetValue,
264
+ feeOptionKey,
265
+ }: UTXOTransferParams | EVMTransferParams | CosmosTransferParams) {
266
+ const chain = assetValue.chain as WalletChain;
267
+ const wallet = getWallet(chain);
268
+ if (!wallet) throw new SwapKitError("core_wallet_connection_not_found");
269
+
270
+ return wallet.transfer({ from, recipient, assetValue, feeOptionKey });
271
+ }
272
+
273
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: TODO clean this up
274
+ async function estimateTransactionFee<T extends PluginName>({
275
+ type,
276
+ feeOptionKey,
277
+ params,
278
+ }: (
279
+ | { type: "swap"; params: SwapParams<T> & { assetValue: AssetValue } }
280
+ | {
281
+ type: "transfer";
282
+ params: UTXOTransferParams | EVMTransferParams | CosmosTransferParams;
283
+ }
284
+ | {
285
+ type: "approve";
286
+ params: {
287
+ assetValue: AssetValue;
288
+ contractAddress: string | PluginName;
289
+ feeOptionKey?: FeeOption;
290
+ };
291
+ }
292
+ ) & {
293
+ feeOptionKey: FeeOption;
294
+ }): Promise<AssetValue | undefined> {
295
+ const { assetValue } = params;
296
+ const { chain } = assetValue;
297
+
298
+ if (!getWallet(chain)) throw new SwapKitError("core_wallet_connection_not_found");
299
+
300
+ const baseValue = AssetValue.from({ chain });
301
+
302
+ switch (chain) {
303
+ case Chain.Arbitrum:
304
+ case Chain.Avalanche:
305
+ case Chain.Ethereum:
306
+ case Chain.BinanceSmartChain:
307
+ case Chain.Polygon: {
308
+ const wallet = getWallet(chain);
309
+ if (type === "transfer") {
310
+ const txObject = await wallet.createTransferTx(params);
311
+ return wallet.estimateTransactionFee(txObject, feeOptionKey);
312
+ }
313
+
314
+ if (type === "approve" && !isGasAsset(assetValue)) {
315
+ return wallet.estimateTransactionFee(
316
+ await wallet.createApprovalTx({
317
+ assetAddress: assetValue.address as string,
318
+ spenderAddress: params.contractAddress as string,
319
+ amount: assetValue.getBaseValue("bigint"),
320
+ from: wallet.address,
321
+ }),
322
+ feeOptionKey,
323
+ );
324
+ }
325
+
326
+ if (type === "swap") {
327
+ const plugin = params.route.providers[0] as PluginNameEnum;
328
+ if (plugin === PluginNameEnum.CHAINFLIP) {
329
+ const txObject = await wallet.createTransferTx({
330
+ from: wallet.address,
331
+ recipient: wallet.address,
332
+ assetValue,
333
+ });
334
+ return wallet.estimateTransactionFee(txObject, feeOptionKey);
335
+ }
336
+
337
+ const { evmTransactionDetails } = params.route;
338
+ if (
339
+ !(
340
+ evmTransactionDetails &&
341
+ lowercasedContractAbiMapping[evmTransactionDetails.contractAddress]
342
+ )
343
+ ) {
344
+ return undefined;
345
+ }
346
+
347
+ return wallet.estimateTransactionFee(
348
+ await wallet.createContractTxObject({
349
+ contractAddress: evmTransactionDetails.contractAddress,
350
+ // biome-ignore lint/style/noNonNullAssertion: TS cant infer the type
351
+ abi: lowercasedContractAbiMapping[evmTransactionDetails.contractAddress]!,
352
+ funcName: evmTransactionDetails.contractMethod,
353
+ funcParams: evmTransactionDetails.contractParams,
354
+ }),
355
+ feeOptionKey,
356
+ );
357
+ }
358
+
359
+ return AssetValue.from({ chain });
360
+ }
361
+
362
+ case Chain.Bitcoin:
363
+ case Chain.BitcoinCash:
364
+ case Chain.Dogecoin:
365
+ case Chain.Dash:
366
+ case Chain.Litecoin: {
367
+ const { estimateMaxSendableAmount, address } = getWallet(chain);
368
+
369
+ return estimateMaxSendableAmount({
370
+ ...params,
371
+ feeOptionKey,
372
+ from: address,
373
+ recipient: address,
374
+ });
375
+ }
376
+
377
+ case Chain.THORChain:
378
+ case Chain.Maya:
379
+ case Chain.Kujira:
380
+ case Chain.Cosmos: {
381
+ return cosmosTransactionFee(params);
382
+ }
383
+
384
+ case Chain.Polkadot: {
385
+ const { address, estimateTransactionFee } = getWallet(chain);
386
+
387
+ return estimateTransactionFee({ ...params, recipient: address });
388
+ }
389
+
390
+ default:
391
+ return baseValue;
392
+ }
393
+ }
394
+
395
+ return {
396
+ ...availablePlugins,
397
+ ...connectWalletMethods,
398
+
399
+ approveAssetValue,
400
+ getAddress,
401
+ getBalance,
402
+ getExplorerAddressUrl: getAddressUrl,
403
+ getExplorerTxUrl: getTxUrl,
404
+ getWallet,
405
+ getAllWallets,
406
+ getWalletWithBalance,
407
+ isAssetValueApproved,
408
+ estimateTransactionFee,
409
+ swap,
410
+ transfer,
411
+ validateAddress,
412
+ disconnectAll,
413
+ disconnectChain,
414
+ };
415
+ }
@@ -0,0 +1,44 @@
1
+ import { Chain, ChainToExplorerUrl, SwapKitError } from "@swapkit/helpers";
2
+
3
+ export function getExplorerTxUrl({ chain, txHash }: { txHash: string; chain: Chain }) {
4
+ const baseUrl = ChainToExplorerUrl[chain];
5
+
6
+ switch (chain) {
7
+ case Chain.Maya:
8
+ case Chain.Kujira:
9
+ case Chain.Cosmos:
10
+ case Chain.THORChain:
11
+ case Chain.Solana:
12
+ return `${baseUrl}/tx/${txHash.startsWith("0x") ? txHash.slice(2) : txHash}`;
13
+
14
+ case Chain.Arbitrum:
15
+ case Chain.Avalanche:
16
+ case Chain.BinanceSmartChain:
17
+ case Chain.Ethereum:
18
+ case Chain.Optimism:
19
+ case Chain.Polkadot:
20
+ case Chain.Polygon:
21
+ return `${baseUrl}/tx/${txHash.startsWith("0x") ? txHash : `0x${txHash}`}`;
22
+
23
+ case Chain.Litecoin:
24
+ case Chain.Bitcoin:
25
+ case Chain.BitcoinCash:
26
+ case Chain.Dogecoin:
27
+ return `${baseUrl}/transaction/${txHash.toLowerCase()}`;
28
+
29
+ default:
30
+ throw new SwapKitError({ errorKey: "core_explorer_unsupported_chain", info: { chain } });
31
+ }
32
+ }
33
+
34
+ export function getExplorerAddressUrl({ chain, address }: { address: string; chain: Chain }) {
35
+ const baseUrl = ChainToExplorerUrl[chain];
36
+
37
+ switch (chain) {
38
+ case Chain.Solana:
39
+ return `${baseUrl}/account/${address}`;
40
+
41
+ default:
42
+ return `${baseUrl}/address/${address}`;
43
+ }
44
+ }