@openocean.finance/widget 1.0.28 → 1.0.29

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 (110) hide show
  1. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js +46 -39
  2. package/dist/esm/components/AmountInput/AmountInputEndAdornment.js.map +1 -1
  3. package/dist/esm/components/Messages/WarningMessages.js +2 -2
  4. package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
  5. package/dist/esm/components/Step/Step.js +37 -29
  6. package/dist/esm/components/Step/Step.js.map +1 -1
  7. package/dist/esm/components/TransactionDetails.js +2 -5
  8. package/dist/esm/components/TransactionDetails.js.map +1 -1
  9. package/dist/esm/config/version.d.ts +1 -1
  10. package/dist/esm/config/version.js +1 -1
  11. package/dist/esm/cross/adapters/AcrossAdapter.d.ts +15 -0
  12. package/dist/esm/cross/adapters/AcrossAdapter.js +166 -0
  13. package/dist/esm/cross/adapters/AcrossAdapter.js.map +1 -0
  14. package/dist/esm/cross/adapters/BaseSwapAdapter.d.ts +107 -0
  15. package/dist/esm/cross/adapters/BaseSwapAdapter.js +44 -0
  16. package/dist/esm/cross/adapters/BaseSwapAdapter.js.map +1 -0
  17. package/dist/esm/cross/adapters/DebridgeAdapter.d.ts +20 -0
  18. package/dist/esm/cross/adapters/DebridgeAdapter.js +264 -0
  19. package/dist/esm/cross/adapters/DebridgeAdapter.js.map +1 -0
  20. package/dist/esm/cross/adapters/LifiAdapter.d.ts +19 -0
  21. package/dist/esm/cross/adapters/LifiAdapter.js +169 -0
  22. package/dist/esm/cross/adapters/LifiAdapter.js.map +1 -0
  23. package/dist/esm/cross/adapters/MayanAdapter.d.ts +14 -0
  24. package/dist/esm/cross/adapters/MayanAdapter.js +119 -0
  25. package/dist/esm/cross/adapters/MayanAdapter.js.map +1 -0
  26. package/dist/esm/cross/adapters/NearIntentsAdapter.d.ts +21 -0
  27. package/dist/esm/cross/adapters/NearIntentsAdapter.js +425 -0
  28. package/dist/esm/cross/adapters/NearIntentsAdapter.js.map +1 -0
  29. package/dist/esm/cross/adapters/OptimexAdapter.d.ts +19 -0
  30. package/dist/esm/cross/adapters/OptimexAdapter.js +216 -0
  31. package/dist/esm/cross/adapters/OptimexAdapter.js.map +1 -0
  32. package/dist/esm/cross/adapters/OrbiterAdapter.d.ts +20 -0
  33. package/dist/esm/cross/adapters/OrbiterAdapter.js +213 -0
  34. package/dist/esm/cross/adapters/OrbiterAdapter.js.map +1 -0
  35. package/dist/esm/cross/adapters/RelayAdapter.d.ts +14 -0
  36. package/dist/esm/cross/adapters/RelayAdapter.js +171 -0
  37. package/dist/esm/cross/adapters/RelayAdapter.js.map +1 -0
  38. package/dist/esm/cross/adapters/SymbiosisAdapter.d.ts +14 -0
  39. package/dist/esm/cross/adapters/SymbiosisAdapter.js +120 -0
  40. package/dist/esm/cross/adapters/SymbiosisAdapter.js.map +1 -0
  41. package/dist/esm/cross/adapters/XYFinanceAdapter.d.ts +14 -0
  42. package/dist/esm/cross/adapters/XYFinanceAdapter.js +177 -0
  43. package/dist/esm/cross/adapters/XYFinanceAdapter.js.map +1 -0
  44. package/dist/esm/cross/adapters/index.d.ts +2 -0
  45. package/dist/esm/cross/adapters/index.js +10 -0
  46. package/dist/esm/cross/adapters/index.js.map +1 -0
  47. package/dist/esm/cross/constants/index.d.ts +202 -0
  48. package/dist/esm/cross/constants/index.js +183 -0
  49. package/dist/esm/cross/constants/index.js.map +1 -0
  50. package/dist/esm/cross/crossChainQuote.d.ts +25 -0
  51. package/dist/esm/cross/crossChainQuote.js +127 -0
  52. package/dist/esm/cross/crossChainQuote.js.map +1 -0
  53. package/dist/esm/cross/factory.d.ts +9 -0
  54. package/dist/esm/cross/factory.js +125 -0
  55. package/dist/esm/cross/factory.js.map +1 -0
  56. package/dist/esm/cross/registry.d.ts +12 -0
  57. package/dist/esm/cross/registry.js +52 -0
  58. package/dist/esm/cross/registry.js.map +1 -0
  59. package/dist/esm/hooks/useChain.d.ts +1 -1
  60. package/dist/esm/hooks/useGasRefuel.d.ts +1 -1
  61. package/dist/esm/hooks/useGasSufficiencyBridge.js +1 -2
  62. package/dist/esm/hooks/useGasSufficiencyBridge.js.map +1 -1
  63. package/dist/esm/hooks/useRouteExecution.js +2 -1
  64. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  65. package/dist/esm/hooks/useRoutes.js +50 -32
  66. package/dist/esm/hooks/useRoutes.js.map +1 -1
  67. package/dist/esm/hooks/useSettingMonitor.js +1 -0
  68. package/dist/esm/hooks/useSettingMonitor.js.map +1 -1
  69. package/dist/esm/hooks/useTokenAddressBalance.d.ts +1 -1
  70. package/dist/esm/hooks/useTokenPrice.js +4 -2
  71. package/dist/esm/hooks/useTokenPrice.js.map +1 -1
  72. package/dist/esm/hooks/useTokens.d.ts +1 -1
  73. package/dist/esm/services/ExecuteRoute.js +142 -124
  74. package/dist/esm/services/ExecuteRoute.js.map +1 -1
  75. package/dist/esm/stores/form/useFieldController.d.ts +1 -1
  76. package/dist/esm/stores/routes/createRouteExecutionStore.js +6 -3
  77. package/dist/esm/stores/routes/createRouteExecutionStore.js.map +1 -1
  78. package/dist/esm/stores/routes/useSetExecutableRoute.d.ts +1 -1
  79. package/dist/esm/types/widget.d.ts +3 -0
  80. package/dist/tsconfig.tsbuildinfo +1 -0
  81. package/package.json +14 -4
  82. package/src/components/AmountInput/AmountInputEndAdornment.tsx +46 -46
  83. package/src/components/Messages/WarningMessages.tsx +7 -2
  84. package/src/components/Step/Step.tsx +37 -31
  85. package/src/components/TransactionDetails.tsx +10 -11
  86. package/src/config/version.ts +1 -1
  87. package/src/cross/adapters/AcrossAdapter.ts +193 -0
  88. package/src/cross/adapters/BaseSwapAdapter.ts +173 -0
  89. package/src/cross/adapters/DebridgeAdapter.ts +375 -0
  90. package/src/cross/adapters/LifiAdapter.ts +213 -0
  91. package/src/cross/adapters/MayanAdapter.ts +179 -0
  92. package/src/cross/adapters/NearIntentsAdapter.ts +539 -0
  93. package/src/cross/adapters/OptimexAdapter.ts +273 -0
  94. package/src/cross/adapters/OrbiterAdapter.ts +270 -0
  95. package/src/cross/adapters/RelayAdapter.ts +248 -0
  96. package/src/cross/adapters/SymbiosisAdapter.ts +144 -0
  97. package/src/cross/adapters/XYFinanceAdapter.ts +213 -0
  98. package/src/cross/adapters/index.ts +9 -0
  99. package/src/cross/constants/index.ts +223 -0
  100. package/src/cross/crossChainQuote.ts +181 -0
  101. package/src/cross/factory.ts +145 -0
  102. package/src/cross/registry.ts +65 -0
  103. package/src/hooks/useGasSufficiencyBridge.ts +1 -3
  104. package/src/hooks/useRouteExecution.ts +2 -1
  105. package/src/hooks/useRoutes.ts +64 -43
  106. package/src/hooks/useSettingMonitor.ts +1 -1
  107. package/src/hooks/useTokenPrice.ts +5 -3
  108. package/src/services/ExecuteRoute.ts +184 -171
  109. package/src/stores/routes/createRouteExecutionStore.ts +13 -4
  110. package/src/types/widget.ts +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openocean.finance/widget",
3
- "version": "1.0.28",
3
+ "version": "1.0.29",
4
4
  "description": "Openocean Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
5
5
  "type": "module",
6
6
  "main": "./dist/esm/index.js",
@@ -48,7 +48,13 @@
48
48
  "@mui/material": "^6.4.8",
49
49
  "@mui/system": "^6.4.8",
50
50
  "@openocean.finance/wallet-management": "^1.0.11",
51
- "@openocean.finance/widget-sdk": "^1.0.8",
51
+ "@openocean.finance/widget-sdk": "^1.0.9",
52
+ "@across-protocol/app-sdk": "^0.2.0",
53
+ "@near-wallet-selector/react-hook": "^9.0.0",
54
+ "@reservoir0x/relay-sdk": "^2.4.0",
55
+ "@lifi/sdk": "^3.6.8",
56
+ "@mayanfinance/swap-sdk": "^11.0.1",
57
+ "@defuse-protocol/one-click-sdk-typescript": "^0.1.2",
52
58
  "@solana/wallet-adapter-base": "^0.9.24",
53
59
  "@solana/web3.js": "^1.98.0",
54
60
  "@tanstack/react-virtual": "^3.13.4",
@@ -74,9 +80,13 @@
74
80
  "@bigmi/react": ">=0.1.0",
75
81
  "@solana/wallet-adapter-react": "^0.15.35",
76
82
  "@tanstack/react-query": "^5.62.0",
77
- "react": ">=18",
78
- "react-dom": ">=18",
83
+ "react": ">=18.0.0",
84
+ "react-dom": ">=18.0.0",
79
85
  "wagmi": "^2.14.0"
80
86
  },
87
+ "peerDependenciesMeta": {
88
+ "react": { "optional": false },
89
+ "react-dom": { "optional": false }
90
+ },
81
91
  "files": ["dist/**", "src/**", "!tsconfig.json"]
82
92
  }
@@ -76,21 +76,21 @@ export const AmountInputEndAdornment = ({ formType }: FormTypeProps) => {
76
76
  )
77
77
  )
78
78
  }
79
- const prependedOperatingExpenseCost = await getCost({
80
- srcChainId: fromChainId === 1151111081099710 ? 7565164 : fromChainId,
81
- srcChainTokenIn: fromTokenAddress,
82
- srcChainTokenInAmount: srcChainTokenInAmount,
83
- dstChainTokenOutAmount: 'auto',
84
- dstChainId: toChainId === 1151111081099710 ? 7565164 : toChainId,
85
- dstChainTokenOut: toTokenAddress,
86
- prependOperatingExpenses: true,
87
- additionalTakerRewardBps: 0,
88
- tab: new Date().getTime(),
89
- })
90
- return prependedOperatingExpenseCost
79
+ // const prependedOperatingExpenseCost = await getCost({
80
+ // srcChainId: fromChainId === 1151111081099710 ? 7565164 : fromChainId,
81
+ // srcChainTokenIn: fromTokenAddress,
82
+ // srcChainTokenInAmount: srcChainTokenInAmount,
83
+ // dstChainTokenOutAmount: 'auto',
84
+ // dstChainId: toChainId === 1151111081099710 ? 7565164 : toChainId,
85
+ // dstChainTokenOut: toTokenAddress,
86
+ // prependOperatingExpenses: true,
87
+ // additionalTakerRewardBps: 0,
88
+ // tab: new Date().getTime(),
89
+ // })
90
+ return 0n
91
91
  },
92
92
  })
93
- let prependedOperatingExpenseCost = prependedOperatingExpenseCostOne || 0
93
+ const prependedOperatingExpenseCost = prependedOperatingExpenseCostOne || 0
94
94
 
95
95
  const handleMax = async () => {
96
96
  if (!token?.amount) {
@@ -101,40 +101,40 @@ export const AmountInputEndAdornment = ({ formType }: FormTypeProps) => {
101
101
  let maxAmount = token.amount
102
102
 
103
103
  let gas = 0n
104
- if (
105
- state === 'bridge' &&
106
- fromChainId !== toChainId &&
107
- fromTokenAddress &&
108
- toTokenAddress
109
- ) {
110
- if (routes) {
111
- const router: any = routes[0] || {
112
- toAmount: 0,
113
- toToken: { decimals: 18 },
114
- }
115
- if (
116
- router &&
117
- router.data &&
118
- router.data.prependedOperatingExpenseCost
119
- ) {
120
- prependedOperatingExpenseCost =
121
- router.data.prependedOperatingExpenseCost
122
- }
123
- }
104
+ // if (
105
+ // state === 'bridge' &&
106
+ // fromChainId !== toChainId &&
107
+ // fromTokenAddress &&
108
+ // toTokenAddress
109
+ // ) {
110
+ // if (routes) {
111
+ // const router: any = routes[0] || {
112
+ // toAmount: 0,
113
+ // toToken: { decimals: 18 },
114
+ // }
115
+ // if (
116
+ // router &&
117
+ // router.data &&
118
+ // router.data.prependedOperatingExpenseCost
119
+ // ) {
120
+ // prependedOperatingExpenseCost =
121
+ // router.data.prependedOperatingExpenseCost
122
+ // }
123
+ // }
124
124
 
125
- gas = BigInt(
126
- Number.parseInt(
127
- (1.15 * Number(prependedOperatingExpenseCost)).toString()
128
- )
129
- )
130
- if (chain?.nativeToken?.address === fromTokenAddress) {
131
- if (fromChainId === 1151111081099710) {
132
- gas += 15000000n + (8157120n + 4000000n + 890880n)
133
- } else if (fromChainId === 8453) {
134
- gas += 1000000000000000n + 1000000000000n
135
- }
136
- }
137
- }
125
+ // gas = BigInt(
126
+ // Number.parseInt(
127
+ // (1.15 * Number(prependedOperatingExpenseCost)).toString()
128
+ // )
129
+ // )
130
+ // if (chain?.nativeToken?.address === fromTokenAddress) {
131
+ // if (fromChainId === 1151111081099710) {
132
+ // gas += 15000000n + (8157120n + 4000000n + 890880n)
133
+ // } else if (fromChainId === 8453) {
134
+ // gas += 1000000000000000n + 1000000000000n
135
+ // }
136
+ // }
137
+ // }
138
138
 
139
139
  if (state === 'swap' || fromChainId === toChainId) {
140
140
  if (
@@ -6,12 +6,12 @@ import { FundsSufficiencyMessage } from './FundsSufficiencyMessage.js'
6
6
  import { GasSufficiencyMessage } from './GasSufficiencyMessage.js'
7
7
  import { GasSufficiencyMessageBridge } from './GasSufficiencyMessageBridge.js'
8
8
  import { PriceImpactHighMessage } from './PriceImpactHighMessage.js'
9
+ import { ServerErrorMessage } from './ServeErrorMessage.js'
9
10
  import { ToAddressRequiredMessage } from './ToAddressRequiredMessage.js'
10
11
  import {
11
12
  useMessageQueue,
12
13
  useStorePriceImpactAcknowledged,
13
14
  } from './useMessageQueue.js'
14
- import { ServerErrorMessage } from './ServeErrorMessage.js'
15
15
 
16
16
  type WarningMessagesProps = BoxProps & {
17
17
  route?: Route
@@ -59,7 +59,12 @@ export const WarningMessages: React.FC<WarningMessagesProps> = ({
59
59
  }
60
60
  return null
61
61
  case 'SERVER_ERROR':
62
- return <ServerErrorMessage errorMsg={messages[0].props?.errorMsg} {...props} />
62
+ return (
63
+ <ServerErrorMessage
64
+ errorMsg={messages[0].props?.errorMsg}
65
+ {...props}
66
+ />
67
+ )
63
68
  default:
64
69
  return null
65
70
  }
@@ -29,10 +29,10 @@ export const Step: React.FC<{
29
29
  )
30
30
 
31
31
  const getCardTitle = () => {
32
- const hasBridgeStep = step.includedSteps.some(
33
- (step) => step.type === 'cross'
34
- )
35
- const hasSwapStep = step.includedSteps.some((step) => step.type === 'swap')
32
+ // const hasBridgeStep = step.includedSteps.some(
33
+ // (step) => step.type === 'cross'
34
+ // )
35
+ // const hasSwapStep = step.includedSteps.some((step) => step.type === 'swap')
36
36
  const hasCustomStep = step.includedSteps.some(
37
37
  (step) => step.type === 'custom'
38
38
  )
@@ -40,33 +40,39 @@ export const Step: React.FC<{
40
40
  const isCustomVariant = hasCustomStep && subvariant === 'custom'
41
41
 
42
42
  switch (step.type) {
43
- case 'openocean': {
44
- if (hasBridgeStep && hasSwapStep) {
45
- return isCustomVariant
46
- ? subvariantOptions?.custom === 'deposit'
47
- ? t('main.stepBridgeAndDeposit')
48
- : t('main.stepBridgeAndBuy')
49
- : t('main.stepSwapAndBridge')
50
- }
51
- if (hasBridgeStep) {
52
- return isCustomVariant
53
- ? subvariantOptions?.custom === 'deposit'
54
- ? t('main.stepBridgeAndDeposit')
55
- : t('main.stepBridgeAndBuy')
56
- : t('main.stepBridge')
57
- }
58
- if (hasSwapStep) {
59
- return isCustomVariant
60
- ? subvariantOptions?.custom === 'deposit'
61
- ? t('main.stepSwapAndDeposit')
62
- : t('main.stepSwapAndBuy')
63
- : t('main.stepSwap')
64
- }
65
- return isCustomVariant
66
- ? subvariantOptions?.custom === 'deposit'
67
- ? t('main.stepDeposit')
68
- : t('main.stepBuy')
69
- : t('main.stepSwap')
43
+ // case 'openocean': {
44
+ // if (hasBridgeStep && hasSwapStep) {
45
+ // return isCustomVariant
46
+ // ? subvariantOptions?.custom === 'deposit'
47
+ // ? t('main.stepBridgeAndDeposit')
48
+ // : t('main.stepBridgeAndBuy')
49
+ // : t('main.stepSwapAndBridge')
50
+ // }
51
+ // if (hasBridgeStep) {
52
+ // return isCustomVariant
53
+ // ? subvariantOptions?.custom === 'deposit'
54
+ // ? t('main.stepBridgeAndDeposit')
55
+ // : t('main.stepBridgeAndBuy')
56
+ // : t('main.stepBridge')
57
+ // }
58
+ // if (hasSwapStep) {
59
+ // return isCustomVariant
60
+ // ? subvariantOptions?.custom === 'deposit'
61
+ // ? t('main.stepSwapAndDeposit')
62
+ // : t('main.stepSwapAndBuy')
63
+ // : t('main.stepSwap')
64
+ // }
65
+ // return isCustomVariant
66
+ // ? subvariantOptions?.custom === 'deposit'
67
+ // ? t('main.stepDeposit')
68
+ // : t('main.stepBuy')
69
+ // : t('main.stepSwap')
70
+ // }
71
+ case 'bridge': {
72
+ return t('main.stepBridge')
73
+ }
74
+ case 'swap': {
75
+ return t('main.stepSwap')
70
76
  }
71
77
  default:
72
78
  return isCustomVariant
@@ -69,19 +69,18 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
69
69
 
70
70
  let gasCostUSD = 0
71
71
  const feeCosts = []
72
- const combinedFeesUSD = gasCostUSD + feeCosts.reduce((sum, fee) => sum + fee.costUSD, 0)
72
+ const combinedFeesUSD =
73
+ gasCostUSD + feeCosts.reduce((sum, fee) => sum + fee.costUSD, 0)
73
74
  const feeCostUSD = feeCosts.reduce((sum, fee) => sum + fee.costUSD, 0)
74
- const estimatedGas = (route as any)?.estimatedGas || (route as any)?.data?.estimatedGas
75
+ const estimatedGas =
76
+ (route as any)?.estimatedGas || (route as any)?.data?.estimatedGas
75
77
  if (token && gasPrice && estimatedGas) {
76
78
  const d = 10 ** token.decimals
77
79
  gasCostUSD =
78
80
  Number(token.priceUSD) * ((Number(gasPrice) * Number(estimatedGas)) / d)
79
81
  }
80
- if (isBradge && (route as any)?.data?.prependedOperatingExpenseCost) {
81
- const decimals = 10 ** route.fromToken.decimals
82
- gasCostUSD =
83
- ((route as any).data.prependedOperatingExpenseCost / decimals) *
84
- Number(route.fromToken.priceUSD)
82
+ if (isBradge) {
83
+ gasCostUSD = (route as any).feeCosts?.[0]?.amountUSD || 0
85
84
  }
86
85
 
87
86
  const { priceImpact } = usePriceImpact(route)
@@ -228,10 +227,10 @@ export const TransactionDetails: React.FC<TransactionDetailsProps> = ({
228
227
  {t('main.fees.provider')}
229
228
  </Typography>
230
229
  {feeCostUSD
231
- ? t('format.currency', {
232
- value: feeCostUSD,
233
- })
234
- : '--'}
230
+ ? t('format.currency', {
231
+ value: feeCostUSD,
232
+ })
233
+ : '--'}
235
234
  </Box>
236
235
  ) : null}
237
236
  {showIntegratorFeeCollectionDetails ? (
@@ -1,2 +1,2 @@
1
1
  export const name = '@openocean.finance/widget'
2
- export const version = '1.0.28'
2
+ export const version = '1.0.29'
@@ -0,0 +1,193 @@
1
+ import { AcrossClient, createAcrossClient } from '@across-protocol/app-sdk'
2
+ import { Currency } from '../constants/index.js'
3
+ import { ChainId } from '@openocean.finance/widget-sdk'
4
+ import { ethers } from 'ethers'
5
+ import { WalletClient, formatUnits } from 'viem'
6
+ import { arbitrum, base, blast, linea, mainnet, optimism, polygon, scroll, unichain, zksync } from 'viem/chains'
7
+
8
+ import { CROSS_CHAIN_FEE_RECEIVER } from '../constants/index.js'
9
+
10
+ import { Quote } from '../registry.js'
11
+ import {
12
+ BaseSwapAdapter,
13
+ Chain,
14
+ EvmQuoteParams,
15
+ NOT_SUPPORTED_CHAINS_PRICE_SERVICE,
16
+ NormalizedQuote,
17
+ NormalizedTxResponse,
18
+ SwapStatus,
19
+ } from './BaseSwapAdapter.js'
20
+
21
+ // Define the ABI of the functions
22
+ const transferFunction = 'function transfer(address to, uint256 amount)'
23
+
24
+ // Create Interface instances
25
+ const erc20Interface = new ethers.utils.Interface([transferFunction])
26
+
27
+ const multicalHandlerContract: Record<string, `0x${string}`> = {
28
+ [ChainId.MAINNET]: '0x924a9f036260DdD5808007E1AA95f08eD08aA569',
29
+ [ChainId.ARBITRUM]: '0x924a9f036260DdD5808007E1AA95f08eD08aA569',
30
+ [ChainId.OPTIMISM]: '0x924a9f036260DdD5808007E1AA95f08eD08aA569',
31
+ [ChainId.LINEA]: '0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB',
32
+ [ChainId.MATIC]: '0x924a9f036260DdD5808007E1AA95f08eD08aA569',
33
+ [ChainId.ZKSYNC]: '0x863859ef502F0Ee9676626ED5B418037252eFeb2',
34
+ [ChainId.BASE]: '0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB',
35
+ [ChainId.SCROLL]: '0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB',
36
+ [ChainId.BLAST]: '0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB',
37
+ [ChainId.UNICHAIN]: '0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB',
38
+ }
39
+
40
+ export class AcrossAdapter extends BaseSwapAdapter {
41
+ private acrossClient: AcrossClient
42
+
43
+ constructor() {
44
+ super()
45
+ this.acrossClient = createAcrossClient({
46
+ integratorId: `0x008a`,
47
+ chains: [mainnet, arbitrum, optimism, linea, polygon, zksync, base, scroll, blast, unichain],
48
+ rpcUrls: {
49
+ [ChainId.BASE]: 'https://base.drpc.org',
50
+ },
51
+ })
52
+ }
53
+
54
+ getName(): string {
55
+ return 'Across'
56
+ }
57
+ getIcon(): string {
58
+ return 'https://across.to/favicon.ico'
59
+ }
60
+ getSupportedChains(): Chain[] {
61
+ return [
62
+ ChainId.MAINNET,
63
+ ChainId.ARBITRUM,
64
+ ChainId.OPTIMISM,
65
+ ChainId.LINEA,
66
+ ChainId.MATIC,
67
+ ChainId.ZKSYNC,
68
+ ChainId.BASE,
69
+ ChainId.SCROLL,
70
+ ChainId.BLAST,
71
+ ChainId.UNICHAIN,
72
+ ]
73
+ }
74
+
75
+ getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
76
+ return []
77
+ }
78
+
79
+ async getQuote(params: EvmQuoteParams): Promise<NormalizedQuote> {
80
+ try {
81
+ const resp = await this.acrossClient.getQuote({
82
+ route: {
83
+ originChainId: +params.fromChain,
84
+ destinationChainId: +params.toChain,
85
+ inputToken: params.fromToken.wrapped.address as `0x${string}`,
86
+ outputToken: params.toToken.wrapped.address as `0x${string}`,
87
+ isNative: params.fromToken.isNative,
88
+ },
89
+ inputAmount: params.amount,
90
+ recipient: multicalHandlerContract[params.toChain],
91
+ crossChainMessage: {
92
+ actions: [
93
+ {
94
+ target: params.toToken.wrapped.address as `0x${string}`,
95
+ callData: erc20Interface.encodeFunctionData('transfer', [CROSS_CHAIN_FEE_RECEIVER, 0n]) as `0x${string}`,
96
+ value: '0',
97
+ update: updatedAmount => ({
98
+ callData: erc20Interface.encodeFunctionData('transfer', [
99
+ CROSS_CHAIN_FEE_RECEIVER,
100
+ (updatedAmount * BigInt(params.feeBps)) / 10_000n,
101
+ ]) as `0x${string}`,
102
+ }),
103
+ },
104
+ ],
105
+ fallbackRecipient: params.recipient as `0x${string}`,
106
+ },
107
+ })
108
+
109
+ // across only have bridge then we can treat token in and out price usd are the same in case price service is not supported
110
+ const isSameToken = params.fromToken.symbol === params.toToken.symbol
111
+ const tokenInUsd =
112
+ isSameToken && NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(params.fromChain) && params.tokenOutUsd
113
+ ? params.tokenOutUsd
114
+ : params.tokenInUsd
115
+ const tokenOutUsd =
116
+ isSameToken && NOT_SUPPORTED_CHAINS_PRICE_SERVICE.includes(params.toChain) && params.tokenInUsd
117
+ ? params.tokenInUsd
118
+ : params.tokenOutUsd
119
+ const feeAmount = (BigInt(resp.deposit.outputAmount) * BigInt(params.feeBps)) / 10_000n
120
+ const formattedOutputAmount = formatUnits(BigInt(resp.deposit.outputAmount) - feeAmount, params.toToken.decimals)
121
+ const formattedInputAmount = formatUnits(BigInt(params.amount), params.fromToken.decimals)
122
+
123
+ const inputUsd = tokenInUsd * +formattedInputAmount
124
+ const outputUsd = tokenOutUsd * +formattedOutputAmount
125
+
126
+ return {
127
+ quoteParams: params,
128
+ outputAmount: BigInt(resp.deposit.outputAmount) - feeAmount,
129
+ formattedOutputAmount,
130
+ inputUsd: tokenInUsd * +formatUnits(BigInt(params.amount), params.fromToken.decimals),
131
+ outputUsd: tokenOutUsd * +formattedOutputAmount,
132
+ rate: +formattedOutputAmount / +formattedInputAmount,
133
+ timeEstimate: resp.estimatedFillTimeSec,
134
+ priceImpact: !inputUsd || !outputUsd ? NaN : ((inputUsd - outputUsd) * 100) / inputUsd,
135
+ // TODO: what is gas fee for across
136
+ gasFeeUsd: 0,
137
+ contractAddress: resp.deposit.spokePoolAddress,
138
+ rawQuote: resp,
139
+
140
+ protocolFee: 0,
141
+ platformFeePercent: (params.feeBps * 100) / 10_000,
142
+ }
143
+ } catch (e) {
144
+ console.log('Across getQuote error', e)
145
+ throw e
146
+ }
147
+ }
148
+
149
+ async executeSwap(quote: Quote, walletClient: WalletClient): Promise<NormalizedTxResponse> {
150
+ return new Promise<NormalizedTxResponse>((resolve, reject) => {
151
+ this.acrossClient
152
+ .executeQuote({
153
+ walletClient: walletClient as any,
154
+ deposit: quote.quote.rawQuote.deposit,
155
+ onProgress: progress => {
156
+ if (progress.step === 'deposit' && 'txHash' in progress) {
157
+ resolve({
158
+ sender: quote.quote.quoteParams.sender,
159
+ sourceTxHash: progress.txHash,
160
+ adapter: this.getName(),
161
+ id: progress.txHash,
162
+ sourceChain: quote.quote.quoteParams.fromChain,
163
+ targetChain: quote.quote.quoteParams.toChain,
164
+ inputAmount: quote.quote.quoteParams.amount,
165
+ outputAmount: quote.quote.outputAmount.toString(),
166
+ sourceToken: quote.quote.quoteParams.fromToken,
167
+ targetToken: quote.quote.quoteParams.toToken,
168
+ timestamp: new Date().getTime(),
169
+ })
170
+ }
171
+ },
172
+ })
173
+ .catch(reject)
174
+ })
175
+ }
176
+ async getTransactionStatus(params: NormalizedTxResponse): Promise<SwapStatus> {
177
+ try {
178
+ const res = await fetch(`https://app.across.to/api/deposit/status?depositTxHash=${params.sourceTxHash}`).then(
179
+ res => res.json(),
180
+ )
181
+ return {
182
+ txHash: res.fillTx || '',
183
+ status: res.status === 'filled' ? 'Success' : 'Processing',
184
+ }
185
+ } catch (error) {
186
+ console.error('Error fetching transaction status:', error)
187
+ return {
188
+ txHash: '',
189
+ status: 'Processing',
190
+ }
191
+ }
192
+ }
193
+ }
@@ -0,0 +1,173 @@
1
+ import type { useWalletSelector } from '@near-wallet-selector/react-hook'
2
+ import { ChainId } from '@openocean.finance/widget-sdk'
3
+ import type { AdaptedWallet } from '@reservoir0x/relay-sdk'
4
+ import type { WalletAdapterProps } from '@solana/wallet-adapter-base'
5
+ import type { Connection } from '@solana/web3.js'
6
+ import type { WalletClient } from 'viem'
7
+
8
+ import type {
9
+ Currency as EvmCurrency,
10
+ NearToken,
11
+ SolanaToken,
12
+ } from '../constants/index.js'
13
+
14
+ import type { Quote } from '../registry.js'
15
+
16
+ export enum NonEvmChain {
17
+ Near = 'near',
18
+ Bitcoin = 'bitcoin',
19
+ Solana = 'solana',
20
+ }
21
+
22
+ export const BitcoinToken = {
23
+ name: 'Bitcoin',
24
+ symbol: 'BTC',
25
+ decimals: 8,
26
+ logo: 'https://storage.googleapis.com/ks-setting-1d682dca/285205e7-a16d-421c-a794-67439cd6b54f1751515894455.png',
27
+ }
28
+
29
+ export type Chain = ChainId | NonEvmChain
30
+ export type Currency =
31
+ | EvmCurrency
32
+ | NearToken
33
+ | typeof BitcoinToken
34
+ | SolanaToken
35
+
36
+ export const NonEvmChainInfo: {
37
+ [key in NonEvmChain]: { name: string; icon: string }
38
+ } = {
39
+ [NonEvmChain.Near]: {
40
+ name: 'NEAR',
41
+ icon: 'https://storage.googleapis.com/ks-setting-1d682dca/000c677f-2ebc-44cc-8d76-e4c6d07627631744962669170.png',
42
+ },
43
+ [NonEvmChain.Bitcoin]: {
44
+ name: 'Bitcoin',
45
+ icon: 'https://storage.googleapis.com/ks-setting-1d682dca/285205e7-a16d-421c-a794-67439cd6b54f1751515894455.png',
46
+ },
47
+ [NonEvmChain.Solana]: {
48
+ name: 'Solana',
49
+ icon: 'https://solana.com/favicon.png',
50
+ },
51
+ }
52
+
53
+ export const NOT_SUPPORTED_CHAINS_PRICE_SERVICE = [
54
+ ChainId.FTM,
55
+ ChainId.SCL,
56
+ ChainId.BLS,
57
+ // ChainId.ZKSYNC,
58
+ // ChainId.HYPEREVM,
59
+ NonEvmChain.Solana,
60
+ NonEvmChain.Bitcoin,
61
+ NonEvmChain.Near,
62
+ ]
63
+
64
+ export interface QuoteParams {
65
+ feeBps: number
66
+ fromChain: Chain
67
+ toChain: Chain
68
+ fromToken: Currency
69
+ toToken: Currency
70
+ amount: string
71
+ slippage: number
72
+ walletClient?: AdaptedWallet | WalletClient
73
+ tokenInUsd: number
74
+ tokenOutUsd: number
75
+ sender: string
76
+ recipient: string
77
+ publicKey?: string
78
+ }
79
+
80
+ export interface EvmQuoteParams extends QuoteParams {
81
+ fromToken: EvmCurrency
82
+ toToken: EvmCurrency
83
+ }
84
+
85
+ export interface NearQuoteParams extends QuoteParams {
86
+ nearTokens: NearToken[]
87
+ }
88
+
89
+ export interface NormalizedQuote {
90
+ quoteParams: QuoteParams
91
+
92
+ outputAmount: bigint
93
+ formattedOutputAmount: string
94
+
95
+ inputUsd: number
96
+ outputUsd: number
97
+
98
+ rate: number
99
+ timeEstimate: number // in seconds
100
+ priceImpact: number // percent
101
+
102
+ gasFeeUsd: number
103
+
104
+ contractAddress: string
105
+
106
+ rawQuote: any
107
+
108
+ protocolFee: number
109
+ protocolFeeString?: string
110
+ platformFeePercent: number
111
+ }
112
+
113
+ export interface NormalizedTxResponse {
114
+ id: string // specific id for each provider
115
+ sourceTxHash: string
116
+ sender: string
117
+ adapter: string
118
+ sourceChain: Chain
119
+ targetChain: Chain
120
+ inputAmount: string
121
+ outputAmount: string
122
+ sourceToken: Currency
123
+ targetToken: Currency
124
+ targetTxHash?: string
125
+ timestamp: number
126
+ status?: 'Processing' | 'Success' | 'Failed' | 'Refunded'
127
+ }
128
+
129
+ export interface SwapStatus {
130
+ txHash: string
131
+ status: 'Processing' | 'Success' | 'Failed' | 'Refunded'
132
+ }
133
+
134
+ // Define a common interface for all swap providers
135
+ export interface SwapProvider {
136
+ getName(): string
137
+ getIcon(): string
138
+ getSupportedChains(): Chain[]
139
+ getSupportedTokens(sourceChain: Chain, destChain: Chain): Currency[]
140
+ getQuote(params: QuoteParams): Promise<NormalizedQuote>
141
+ executeSwap(
142
+ quote: Quote,
143
+ walletClient: WalletClient,
144
+ nearWallet?: ReturnType<typeof useWalletSelector>,
145
+ sendBtcFn?: (params: {
146
+ recipient: string
147
+ amount: string | number
148
+ }) => Promise<string>,
149
+ sendSolanaTransaction?: WalletAdapterProps['sendTransaction'],
150
+ connection?: Connection
151
+ ): Promise<NormalizedTxResponse>
152
+ getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus>
153
+ }
154
+ export abstract class BaseSwapAdapter implements SwapProvider {
155
+ abstract getName(): string
156
+ abstract getIcon(): string
157
+ abstract getSupportedChains(): Chain[]
158
+ abstract getSupportedTokens(sourceChain: Chain, destChain: Chain): Currency[]
159
+ abstract getQuote(params: QuoteParams): Promise<NormalizedQuote>
160
+ abstract executeSwap(
161
+ params: Quote,
162
+ walletClient: WalletClient,
163
+ nearWallet?: ReturnType<typeof useWalletSelector>
164
+ ): Promise<NormalizedTxResponse>
165
+ abstract getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus>
166
+
167
+ protected handleError(error: any): never {
168
+ console.error(`[${this.getName()}] Error:`, error)
169
+ throw new Error(
170
+ `${this.getName()} provider error: ${error.message || 'Unknown error'}`
171
+ )
172
+ }
173
+ }