@eth-optimism/actions-sdk 0.2.0 → 0.3.0

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 (271) hide show
  1. package/dist/__mocks__/MockAssets.d.ts.map +1 -1
  2. package/dist/__mocks__/MockAssets.js +2 -0
  3. package/dist/__mocks__/MockAssets.js.map +1 -1
  4. package/dist/__tests__/actions.test.js +0 -4
  5. package/dist/__tests__/actions.test.js.map +1 -1
  6. package/dist/actions.d.ts +20 -1
  7. package/dist/actions.d.ts.map +1 -1
  8. package/dist/actions.js +37 -13
  9. package/dist/actions.js.map +1 -1
  10. package/dist/constants/assets.d.ts +4 -0
  11. package/dist/constants/assets.d.ts.map +1 -1
  12. package/dist/constants/assets.js +15 -0
  13. package/dist/constants/assets.js.map +1 -1
  14. package/dist/constants/contracts.d.ts +4 -0
  15. package/dist/constants/contracts.d.ts.map +1 -0
  16. package/dist/constants/contracts.js +3 -0
  17. package/dist/constants/contracts.js.map +1 -0
  18. package/dist/index.d.ts +4 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/lend/core/LendProvider.d.ts +0 -6
  23. package/dist/lend/core/LendProvider.d.ts.map +1 -1
  24. package/dist/lend/core/LendProvider.js +6 -15
  25. package/dist/lend/core/LendProvider.js.map +1 -1
  26. package/dist/lend/core/__tests__/LendProvider.test.js +2 -4
  27. package/dist/lend/core/__tests__/LendProvider.test.js.map +1 -1
  28. package/dist/lend/providers/morpho/__tests__/sdk.test.js +3 -2
  29. package/dist/lend/providers/morpho/__tests__/sdk.test.js.map +1 -1
  30. package/dist/lend/providers/morpho/api.d.ts +4 -0
  31. package/dist/lend/providers/morpho/api.d.ts.map +1 -1
  32. package/dist/lend/providers/morpho/api.js.map +1 -1
  33. package/dist/lend/providers/morpho/sdk.d.ts.map +1 -1
  34. package/dist/lend/providers/morpho/sdk.js +10 -1
  35. package/dist/lend/providers/morpho/sdk.js.map +1 -1
  36. package/dist/supported/tokens.d.ts.map +1 -1
  37. package/dist/supported/tokens.js +9 -2
  38. package/dist/supported/tokens.js.map +1 -1
  39. package/dist/swap/__mocks__/MockSwapProvider.d.ts +38 -0
  40. package/dist/swap/__mocks__/MockSwapProvider.d.ts.map +1 -0
  41. package/dist/swap/__mocks__/MockSwapProvider.js +138 -0
  42. package/dist/swap/__mocks__/MockSwapProvider.js.map +1 -0
  43. package/dist/swap/core/SwapProvider.d.ts +56 -0
  44. package/dist/swap/core/SwapProvider.d.ts.map +1 -0
  45. package/dist/swap/core/SwapProvider.js +177 -0
  46. package/dist/swap/core/SwapProvider.js.map +1 -0
  47. package/dist/swap/core/__tests__/SwapProvider.test.d.ts +2 -0
  48. package/dist/swap/core/__tests__/SwapProvider.test.d.ts.map +1 -0
  49. package/dist/swap/core/__tests__/SwapProvider.test.js +329 -0
  50. package/dist/swap/core/__tests__/SwapProvider.test.js.map +1 -0
  51. package/dist/swap/index.d.ts +7 -0
  52. package/dist/swap/index.d.ts.map +1 -0
  53. package/dist/swap/index.js +8 -0
  54. package/dist/swap/index.js.map +1 -0
  55. package/dist/swap/namespaces/ActionsSwapNamespace.d.ts +8 -0
  56. package/dist/swap/namespaces/ActionsSwapNamespace.d.ts.map +1 -0
  57. package/dist/swap/namespaces/ActionsSwapNamespace.js +8 -0
  58. package/dist/swap/namespaces/ActionsSwapNamespace.js.map +1 -0
  59. package/dist/swap/namespaces/BaseSwapNamespace.d.ts +33 -0
  60. package/dist/swap/namespaces/BaseSwapNamespace.d.ts.map +1 -0
  61. package/dist/swap/namespaces/BaseSwapNamespace.js +58 -0
  62. package/dist/swap/namespaces/BaseSwapNamespace.js.map +1 -0
  63. package/dist/swap/namespaces/WalletSwapNamespace.d.ts +22 -0
  64. package/dist/swap/namespaces/WalletSwapNamespace.d.ts.map +1 -0
  65. package/dist/swap/namespaces/WalletSwapNamespace.js +60 -0
  66. package/dist/swap/namespaces/WalletSwapNamespace.js.map +1 -0
  67. package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.d.ts +2 -0
  68. package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.d.ts.map +1 -0
  69. package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.js +106 -0
  70. package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.js.map +1 -0
  71. package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.d.ts +2 -0
  72. package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.d.ts.map +1 -0
  73. package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.js +132 -0
  74. package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.js.map +1 -0
  75. package/dist/swap/providers/uniswap/UniswapSwapProvider.d.ts +68 -0
  76. package/dist/swap/providers/uniswap/UniswapSwapProvider.d.ts.map +1 -0
  77. package/dist/swap/providers/uniswap/UniswapSwapProvider.js +206 -0
  78. package/dist/swap/providers/uniswap/UniswapSwapProvider.js.map +1 -0
  79. package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.d.ts +2 -0
  80. package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.d.ts.map +1 -0
  81. package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.js +257 -0
  82. package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.js.map +1 -0
  83. package/dist/swap/providers/uniswap/__tests__/sdk.test.d.ts +2 -0
  84. package/dist/swap/providers/uniswap/__tests__/sdk.test.d.ts.map +1 -0
  85. package/dist/swap/providers/uniswap/__tests__/sdk.test.js +312 -0
  86. package/dist/swap/providers/uniswap/__tests__/sdk.test.js.map +1 -0
  87. package/dist/swap/providers/uniswap/abis.d.ts +227 -0
  88. package/dist/swap/providers/uniswap/abis.d.ts.map +1 -0
  89. package/dist/swap/providers/uniswap/abis.js +138 -0
  90. package/dist/swap/providers/uniswap/abis.js.map +1 -0
  91. package/dist/swap/providers/uniswap/addresses.d.ts +21 -0
  92. package/dist/swap/providers/uniswap/addresses.d.ts.map +1 -0
  93. package/dist/swap/providers/uniswap/addresses.js +81 -0
  94. package/dist/swap/providers/uniswap/addresses.js.map +1 -0
  95. package/dist/swap/providers/uniswap/encoding.d.ts +77 -0
  96. package/dist/swap/providers/uniswap/encoding.d.ts.map +1 -0
  97. package/dist/swap/providers/uniswap/encoding.js +233 -0
  98. package/dist/swap/providers/uniswap/encoding.js.map +1 -0
  99. package/dist/swap/providers/uniswap/types.d.ts +20 -0
  100. package/dist/swap/providers/uniswap/types.d.ts.map +1 -0
  101. package/dist/swap/providers/uniswap/types.js +2 -0
  102. package/dist/swap/providers/uniswap/types.js.map +1 -0
  103. package/dist/types/actions.d.ts +19 -5
  104. package/dist/types/actions.d.ts.map +1 -1
  105. package/dist/types/index.d.ts +2 -0
  106. package/dist/types/index.d.ts.map +1 -1
  107. package/dist/types/index.js +2 -0
  108. package/dist/types/index.js.map +1 -1
  109. package/dist/types/lend/base.d.ts +3 -13
  110. package/dist/types/lend/base.d.ts.map +1 -1
  111. package/dist/types/lend/base.js.map +1 -1
  112. package/dist/types/swap/base.d.ts +238 -0
  113. package/dist/types/swap/base.d.ts.map +1 -0
  114. package/dist/types/swap/base.js +4 -0
  115. package/dist/types/swap/base.js.map +1 -0
  116. package/dist/types/swap/index.d.ts +2 -0
  117. package/dist/types/swap/index.d.ts.map +1 -0
  118. package/dist/types/swap/index.js +2 -0
  119. package/dist/types/swap/index.js.map +1 -0
  120. package/dist/types/transaction.d.ts +14 -0
  121. package/dist/types/transaction.d.ts.map +1 -0
  122. package/dist/types/transaction.js +2 -0
  123. package/dist/types/transaction.js.map +1 -0
  124. package/dist/utils/assets.d.ts +4 -5
  125. package/dist/utils/assets.d.ts.map +1 -1
  126. package/dist/utils/assets.js +4 -11
  127. package/dist/utils/assets.js.map +1 -1
  128. package/dist/utils/assets.test.js +13 -1
  129. package/dist/utils/assets.test.js.map +1 -1
  130. package/dist/utils/permit2.d.ts +46 -0
  131. package/dist/utils/permit2.d.ts.map +1 -0
  132. package/dist/utils/permit2.js +100 -0
  133. package/dist/utils/permit2.js.map +1 -0
  134. package/dist/utils/permit2.test.d.ts +2 -0
  135. package/dist/utils/permit2.test.d.ts.map +1 -0
  136. package/dist/utils/permit2.test.js +110 -0
  137. package/dist/utils/permit2.test.js.map +1 -0
  138. package/dist/utils/validation.d.ts +12 -0
  139. package/dist/utils/validation.d.ts.map +1 -0
  140. package/dist/utils/validation.js +44 -0
  141. package/dist/utils/validation.js.map +1 -0
  142. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts +7 -1
  143. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts.map +1 -1
  144. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js +2 -1
  145. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js.map +1 -1
  146. package/dist/wallet/core/providers/hosted/types/index.d.ts +5 -1
  147. package/dist/wallet/core/providers/hosted/types/index.d.ts.map +1 -1
  148. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts +7 -1
  149. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts.map +1 -1
  150. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js +5 -1
  151. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js.map +1 -1
  152. package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js +2 -2
  153. package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js.map +1 -1
  154. package/dist/wallet/core/wallets/abstract/Wallet.d.ts +13 -2
  155. package/dist/wallet/core/wallets/abstract/Wallet.d.ts.map +1 -1
  156. package/dist/wallet/core/wallets/abstract/Wallet.js +7 -1
  157. package/dist/wallet/core/wallets/abstract/Wallet.js.map +1 -1
  158. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts +7 -2
  159. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts.map +1 -1
  160. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js +6 -5
  161. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js.map +1 -1
  162. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +6 -1
  163. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
  164. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js +3 -1
  165. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
  166. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.d.ts.map +1 -1
  167. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js +4 -3
  168. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js.map +1 -1
  169. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +5 -1
  170. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
  171. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +4 -2
  172. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
  173. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts +6 -1
  174. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
  175. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js +4 -3
  176. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js.map +1 -1
  177. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts +5 -1
  178. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
  179. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
  180. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
  181. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts +7 -1
  182. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts.map +1 -1
  183. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js +6 -2
  184. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js.map +1 -1
  185. package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js +1 -0
  186. package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js.map +1 -1
  187. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +6 -1
  188. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
  189. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js +5 -2
  190. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
  191. package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js +1 -0
  192. package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js.map +1 -1
  193. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +6 -3
  194. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
  195. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +5 -4
  196. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
  197. package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.d.ts.map +1 -1
  198. package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js +6 -6
  199. package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js.map +1 -1
  200. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts +7 -1
  201. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts.map +1 -1
  202. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js +5 -3
  203. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js.map +1 -1
  204. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts +5 -1
  205. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
  206. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js +3 -3
  207. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js.map +1 -1
  208. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts +5 -1
  209. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
  210. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
  211. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
  212. package/package.json +2 -2
  213. package/src/__mocks__/MockAssets.ts +2 -0
  214. package/src/__tests__/actions.test.ts +0 -4
  215. package/src/actions.ts +57 -19
  216. package/src/constants/assets.ts +16 -0
  217. package/src/constants/contracts.ts +5 -0
  218. package/src/index.ts +30 -2
  219. package/src/lend/core/LendProvider.ts +6 -18
  220. package/src/lend/core/__tests__/LendProvider.test.ts +2 -5
  221. package/src/lend/providers/morpho/__tests__/sdk.test.ts +3 -2
  222. package/src/lend/providers/morpho/api.ts +4 -0
  223. package/src/lend/providers/morpho/sdk.ts +10 -1
  224. package/src/supported/tokens.ts +16 -2
  225. package/src/swap/__mocks__/MockSwapProvider.ts +216 -0
  226. package/src/swap/core/SwapProvider.ts +319 -0
  227. package/src/swap/core/__tests__/SwapProvider.test.ts +478 -0
  228. package/src/swap/index.ts +14 -0
  229. package/src/swap/namespaces/ActionsSwapNamespace.ts +7 -0
  230. package/src/swap/namespaces/BaseSwapNamespace.ts +77 -0
  231. package/src/swap/namespaces/WalletSwapNamespace.ts +82 -0
  232. package/src/swap/namespaces/__tests__/BaseSwapNamespace.spec.ts +138 -0
  233. package/src/swap/namespaces/__tests__/WalletSwapNamespace.spec.ts +162 -0
  234. package/src/swap/providers/uniswap/UniswapSwapProvider.ts +304 -0
  235. package/src/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.ts +299 -0
  236. package/src/swap/providers/uniswap/__tests__/sdk.test.ts +370 -0
  237. package/src/swap/providers/uniswap/abis.ts +144 -0
  238. package/src/swap/providers/uniswap/addresses.ts +108 -0
  239. package/src/swap/providers/uniswap/encoding.ts +406 -0
  240. package/src/swap/providers/uniswap/types.ts +24 -0
  241. package/src/types/actions.ts +22 -6
  242. package/src/types/index.ts +2 -0
  243. package/src/types/lend/base.ts +4 -14
  244. package/src/types/swap/base.ts +259 -0
  245. package/src/types/swap/index.ts +1 -0
  246. package/src/types/transaction.ts +14 -0
  247. package/src/utils/assets.test.ts +16 -1
  248. package/src/utils/assets.ts +13 -10
  249. package/src/utils/permit2.test.ts +142 -0
  250. package/src/utils/permit2.ts +144 -0
  251. package/src/utils/validation.ts +76 -0
  252. package/src/wallet/core/providers/hosted/abstract/HostedWalletProvider.ts +9 -1
  253. package/src/wallet/core/providers/hosted/types/index.ts +5 -1
  254. package/src/wallet/core/providers/smart/default/DefaultSmartWalletProvider.ts +13 -1
  255. package/src/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.ts +2 -0
  256. package/src/wallet/core/wallets/abstract/Wallet.ts +18 -2
  257. package/src/wallet/core/wallets/smart/default/DefaultSmartWallet.ts +14 -5
  258. package/src/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.ts +13 -2
  259. package/src/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.ts +10 -2
  260. package/src/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +8 -2
  261. package/src/wallet/node/wallets/hosted/privy/PrivyWallet.ts +11 -2
  262. package/src/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.ts +10 -2
  263. package/src/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.ts +10 -2
  264. package/src/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.ts +1 -0
  265. package/src/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.ts +9 -2
  266. package/src/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.ts +1 -0
  267. package/src/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +9 -4
  268. package/src/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.ts +18 -6
  269. package/src/wallet/react/wallets/hosted/dynamic/DynamicWallet.ts +12 -2
  270. package/src/wallet/react/wallets/hosted/privy/PrivyWallet.ts +10 -2
  271. package/src/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.ts +10 -2
@@ -0,0 +1,138 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import type { SupportedChainId } from '@/constants/supportedChains.js'
4
+ import {
5
+ createMockSwapProvider,
6
+ MockSwapProvider,
7
+ } from '@/swap/__mocks__/MockSwapProvider.js'
8
+ import { ActionsSwapNamespace } from '@/swap/namespaces/ActionsSwapNamespace.js'
9
+
10
+ describe('BaseSwapNamespace', () => {
11
+ const USDC = {
12
+ type: 'erc20' as const,
13
+ address: { 84532: '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as const },
14
+ metadata: { name: 'USD Coin', symbol: 'USDC', decimals: 6 },
15
+ }
16
+ const ETH = {
17
+ type: 'native' as const,
18
+ address: { 84532: '0x0000000000000000000000000000000000000000' as const },
19
+ metadata: { name: 'Ether', symbol: 'ETH', decimals: 18 },
20
+ }
21
+
22
+ describe('price', () => {
23
+ it('delegates to provider getPrice', async () => {
24
+ const provider = createMockSwapProvider()
25
+ const namespace = new ActionsSwapNamespace({ uniswap: provider })
26
+
27
+ const result = await namespace.price({
28
+ assetIn: USDC,
29
+ assetOut: ETH,
30
+ amountIn: 100,
31
+ chainId: 84532 as SupportedChainId,
32
+ })
33
+
34
+ expect(provider.mockGetPrice).toHaveBeenCalledTimes(1)
35
+ expect(result.price).toBe('1.5')
36
+ })
37
+
38
+ it('throws if no provider configured', async () => {
39
+ const namespace = new ActionsSwapNamespace({})
40
+
41
+ await expect(
42
+ namespace.price({
43
+ assetIn: USDC,
44
+ assetOut: ETH,
45
+ amountIn: 100,
46
+ chainId: 84532 as SupportedChainId,
47
+ }),
48
+ ).rejects.toThrow('No swap provider configured')
49
+ })
50
+ })
51
+
52
+ describe('getMarket', () => {
53
+ it('delegates to provider getMarket', async () => {
54
+ const provider = createMockSwapProvider()
55
+ const namespace = new ActionsSwapNamespace({ uniswap: provider })
56
+
57
+ const result = await namespace.getMarket({
58
+ poolId: '0xpool123',
59
+ chainId: 84532 as SupportedChainId,
60
+ })
61
+
62
+ expect(provider.mockGetMarket).toHaveBeenCalledTimes(1)
63
+ expect(result.marketId.poolId).toBe('0xpool123')
64
+ })
65
+ })
66
+
67
+ describe('getMarkets', () => {
68
+ it('aggregates markets from all providers', async () => {
69
+ const provider1 = createMockSwapProvider()
70
+ const provider2 = new MockSwapProvider(undefined, {
71
+ supportedChains: [84532 as SupportedChainId],
72
+ })
73
+
74
+ const namespace = new ActionsSwapNamespace({
75
+ uniswap: provider1,
76
+ })
77
+
78
+ // Add second provider manually for testing aggregation
79
+ ;(namespace as any).providers.oneInch = provider2
80
+
81
+ const result = await namespace.getMarkets({})
82
+
83
+ expect(result.length).toBeGreaterThanOrEqual(1)
84
+ expect(provider1.mockGetMarkets).toHaveBeenCalledTimes(1)
85
+ expect(provider2.mockGetMarkets).toHaveBeenCalledTimes(1)
86
+ })
87
+
88
+ it('returns empty array when no providers', async () => {
89
+ const namespace = new ActionsSwapNamespace({})
90
+
91
+ const result = await namespace.getMarkets({})
92
+
93
+ expect(result).toEqual([])
94
+ })
95
+ })
96
+
97
+ describe('supportedChainIds', () => {
98
+ it('returns union of chains from all providers', () => {
99
+ const provider1 = createMockSwapProvider(undefined, {
100
+ supportedChains: [84532 as SupportedChainId],
101
+ })
102
+ const provider2 = new MockSwapProvider(undefined, {
103
+ supportedChains: [1 as SupportedChainId, 10 as SupportedChainId],
104
+ })
105
+
106
+ const namespace = new ActionsSwapNamespace({
107
+ uniswap: provider1,
108
+ })
109
+ ;(namespace as any).providers.oneInch = provider2
110
+
111
+ const result = namespace.supportedChainIds()
112
+
113
+ expect(result).toContain(84532)
114
+ expect(result).toContain(1)
115
+ expect(result).toContain(10)
116
+ expect(result.length).toBe(3)
117
+ })
118
+
119
+ it('deduplicates chain IDs', () => {
120
+ const provider1 = createMockSwapProvider(undefined, {
121
+ supportedChains: [84532 as SupportedChainId, 1 as SupportedChainId],
122
+ })
123
+ const provider2 = new MockSwapProvider(undefined, {
124
+ supportedChains: [1 as SupportedChainId],
125
+ })
126
+
127
+ const namespace = new ActionsSwapNamespace({
128
+ uniswap: provider1,
129
+ })
130
+ ;(namespace as any).providers.oneInch = provider2
131
+
132
+ const result = namespace.supportedChainIds()
133
+
134
+ // Should have unique values only
135
+ expect(new Set(result).size).toBe(result.length)
136
+ })
137
+ })
138
+ })
@@ -0,0 +1,162 @@
1
+ import type { Address } from 'viem'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+
4
+ import type { SupportedChainId } from '@/constants/supportedChains.js'
5
+ import { createMockSwapProvider } from '@/swap/__mocks__/MockSwapProvider.js'
6
+ import { WalletSwapNamespace } from '@/swap/namespaces/WalletSwapNamespace.js'
7
+ import type { Wallet } from '@/wallet/core/wallets/abstract/Wallet.js'
8
+
9
+ describe('WalletSwapNamespace', () => {
10
+ const USDC = {
11
+ type: 'erc20' as const,
12
+ address: { 84532: '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as const },
13
+ metadata: { name: 'USD Coin', symbol: 'USDC', decimals: 6 },
14
+ }
15
+ const ETH = {
16
+ type: 'native' as const,
17
+ address: { 84532: '0x0000000000000000000000000000000000000000' as const },
18
+ metadata: { name: 'Ether', symbol: 'ETH', decimals: 18 },
19
+ }
20
+
21
+ const mockWalletAddress =
22
+ '0x1234567890123456789012345678901234567890' as Address
23
+
24
+ function createMockWallet(): Wallet {
25
+ return {
26
+ address: mockWalletAddress,
27
+ send: vi.fn().mockResolvedValue({ transactionHash: '0xtx1' }),
28
+ sendBatch: vi.fn().mockResolvedValue({ transactionHash: '0xtx2' }),
29
+ } as unknown as Wallet
30
+ }
31
+
32
+ describe('execute', () => {
33
+ it('executes swap with single transaction', async () => {
34
+ const provider = createMockSwapProvider()
35
+ const wallet = createMockWallet()
36
+ const namespace = new WalletSwapNamespace({ uniswap: provider }, wallet)
37
+
38
+ const result = await namespace.execute({
39
+ amountIn: 100,
40
+ assetIn: USDC,
41
+ assetOut: ETH,
42
+ chainId: 84532 as SupportedChainId,
43
+ })
44
+
45
+ expect(provider.mockExecute).toHaveBeenCalledTimes(1)
46
+ expect(wallet.send).toHaveBeenCalledTimes(1)
47
+ expect(wallet.sendBatch).not.toHaveBeenCalled()
48
+ expect(result.price).toBe('1.5')
49
+ expect(result.assetIn).toBe(USDC)
50
+ expect(result.assetOut).toBe(ETH)
51
+ })
52
+
53
+ it('batches transactions when approvals needed', async () => {
54
+ const provider = createMockSwapProvider()
55
+ const wallet = createMockWallet()
56
+ const namespace = new WalletSwapNamespace({ uniswap: provider }, wallet)
57
+
58
+ // Override mock to return transaction with approvals
59
+ provider.mockExecute.mockResolvedValueOnce({
60
+ amountIn: 100,
61
+ amountOut: 1.5,
62
+ amountInWei: 100000000n,
63
+ amountOutWei: 1500000000000000000n,
64
+ assetIn: USDC,
65
+ assetOut: ETH,
66
+ price: '1.5',
67
+ priceImpact: 0.001,
68
+ transactionData: {
69
+ tokenApproval: {
70
+ to: '0xpermit2' as Address,
71
+ data: '0xapprove' as `0x${string}`,
72
+ value: 0n,
73
+ },
74
+ permit2Approval: {
75
+ to: '0xpermit2' as Address,
76
+ data: '0xpermit' as `0x${string}`,
77
+ value: 0n,
78
+ },
79
+ swap: {
80
+ to: '0xrouter' as Address,
81
+ data: '0xswap' as `0x${string}`,
82
+ value: 0n,
83
+ },
84
+ },
85
+ })
86
+
87
+ await namespace.execute({
88
+ amountIn: 100,
89
+ assetIn: USDC,
90
+ assetOut: ETH,
91
+ chainId: 84532 as SupportedChainId,
92
+ })
93
+
94
+ expect(wallet.sendBatch).toHaveBeenCalledTimes(1)
95
+ expect(wallet.send).not.toHaveBeenCalled()
96
+
97
+ // Verify all 3 transactions were batched
98
+ const batchCall = vi.mocked(wallet.sendBatch).mock.calls[0]
99
+ expect(batchCall[0]).toHaveLength(3)
100
+ })
101
+
102
+ it('passes wallet address to provider', async () => {
103
+ const provider = createMockSwapProvider()
104
+ const wallet = createMockWallet()
105
+ const namespace = new WalletSwapNamespace({ uniswap: provider }, wallet)
106
+
107
+ await namespace.execute({
108
+ amountIn: 100,
109
+ assetIn: USDC,
110
+ assetOut: ETH,
111
+ chainId: 84532 as SupportedChainId,
112
+ })
113
+
114
+ expect(provider.mockExecute).toHaveBeenCalledWith(
115
+ expect.objectContaining({
116
+ walletAddress: mockWalletAddress,
117
+ }),
118
+ )
119
+ })
120
+
121
+ it('throws when no provider configured', async () => {
122
+ const wallet = createMockWallet()
123
+ const namespace = new WalletSwapNamespace({}, wallet)
124
+
125
+ await expect(
126
+ namespace.execute({
127
+ amountIn: 100,
128
+ assetIn: USDC,
129
+ assetOut: ETH,
130
+ chainId: 84532 as SupportedChainId,
131
+ }),
132
+ ).rejects.toThrow('No swap provider configured')
133
+ })
134
+ })
135
+
136
+ describe('inherits read-only methods', () => {
137
+ it('has price method from BaseSwapNamespace', async () => {
138
+ const provider = createMockSwapProvider()
139
+ const wallet = createMockWallet()
140
+ const namespace = new WalletSwapNamespace({ uniswap: provider }, wallet)
141
+
142
+ const result = await namespace.price({
143
+ assetIn: USDC,
144
+ assetOut: ETH,
145
+ amountIn: 100,
146
+ chainId: 84532 as SupportedChainId,
147
+ })
148
+
149
+ expect(result.price).toBe('1.5')
150
+ })
151
+
152
+ it('has getMarkets method from BaseSwapNamespace', async () => {
153
+ const provider = createMockSwapProvider()
154
+ const wallet = createMockWallet()
155
+ const namespace = new WalletSwapNamespace({ uniswap: provider }, wallet)
156
+
157
+ const result = await namespace.getMarkets({})
158
+
159
+ expect(result.length).toBeGreaterThanOrEqual(1)
160
+ })
161
+ })
162
+ })
@@ -0,0 +1,304 @@
1
+ import { type Address, encodeAbiParameters, formatUnits, keccak256 } from 'viem'
2
+
3
+ import type { SupportedChainId } from '@/constants/supportedChains.js'
4
+ import { SwapProvider } from '@/swap/core/SwapProvider.js'
5
+ import { POOL_KEY_ABI_TYPE } from '@/swap/providers/uniswap/abis.js'
6
+ import {
7
+ getSupportedChainIds,
8
+ getUniswapAddresses,
9
+ } from '@/swap/providers/uniswap/addresses.js'
10
+ import {
11
+ encodeUniversalRouterSwap,
12
+ getQuote,
13
+ } from '@/swap/providers/uniswap/encoding.js'
14
+ import type {
15
+ UniswapMarketConfig,
16
+ UniswapSwapProviderConfig,
17
+ } from '@/swap/providers/uniswap/types.js'
18
+ import type { Asset } from '@/types/asset.js'
19
+ import type {
20
+ GetSwapMarketParams,
21
+ GetSwapMarketsParams,
22
+ ResolvedSwapParams,
23
+ SwapMarket,
24
+ SwapPrice,
25
+ SwapPriceParams,
26
+ SwapTransaction,
27
+ } from '@/types/swap/index.js'
28
+ import type { TransactionData } from '@/types/transaction.js'
29
+ import { isNativeAsset, parseAssetAmount } from '@/utils/assets.js'
30
+
31
+ /**
32
+ * Uniswap V4 swap provider using Universal Router and Permit2 approvals.
33
+ */
34
+ export class UniswapSwapProvider extends SwapProvider<UniswapSwapProviderConfig> {
35
+ /** @returns Chain IDs where Uniswap V4 contracts are deployed */
36
+ supportedChainIds(): SupportedChainId[] {
37
+ return getSupportedChainIds()
38
+ }
39
+
40
+ /**
41
+ * Build a swap transaction with quote, calldata, and any required approvals.
42
+ * @param params - Resolved swap parameters (amounts in wei, defaults applied)
43
+ * @returns Transaction data ready for wallet execution
44
+ */
45
+ protected async _execute(
46
+ params: ResolvedSwapParams,
47
+ ): Promise<SwapTransaction> {
48
+ const { chainId, assetIn, assetOut } = params
49
+ const addresses = getUniswapAddresses(chainId)
50
+ const publicClient = this.chainManager.getPublicClient(chainId)
51
+ const marketConfig = this.resolveUniswapConfig(assetIn, assetOut, chainId)
52
+
53
+ const quote = await getQuote({
54
+ assetIn,
55
+ assetOut,
56
+ amountInWei: params.amountInWei,
57
+ amountOutWei: params.amountOutWei,
58
+ chainId,
59
+ publicClient,
60
+ quoterAddress: addresses.quoter,
61
+ poolManagerAddress: addresses.poolManager,
62
+ fee: marketConfig.fee,
63
+ tickSpacing: marketConfig.tickSpacing,
64
+ })
65
+
66
+ const swapCalldata = encodeUniversalRouterSwap({
67
+ amountInWei: params.amountInWei,
68
+ amountOutWei: params.amountOutWei,
69
+ assetIn,
70
+ assetOut,
71
+ slippage: params.slippage,
72
+ deadline: params.deadline,
73
+ recipient: params.recipient,
74
+ chainId,
75
+ quote,
76
+ universalRouterAddress: addresses.universalRouter,
77
+ fee: marketConfig.fee,
78
+ tickSpacing: marketConfig.tickSpacing,
79
+ })
80
+
81
+ const amountInWei = params.amountInWei ?? quote.amountInWei
82
+ const { tokenApproval, permit2Approval } = await this.buildPermit2Approvals(
83
+ params,
84
+ amountInWei,
85
+ addresses.permit2,
86
+ addresses.universalRouter,
87
+ this._config.permit2ExpirySeconds,
88
+ )
89
+
90
+ const swapTx: TransactionData = {
91
+ to: addresses.universalRouter,
92
+ data: swapCalldata,
93
+ value: isNativeAsset(assetIn) ? (params.amountInWei ?? 0n) : 0n,
94
+ }
95
+
96
+ return {
97
+ amountIn: parseFloat(formatUnits(amountInWei, assetIn.metadata.decimals)),
98
+ amountOut: parseFloat(
99
+ formatUnits(quote.amountOutWei, assetOut.metadata.decimals),
100
+ ),
101
+ amountInWei,
102
+ amountOutWei: quote.amountOutWei,
103
+ assetIn,
104
+ assetOut,
105
+ price: quote.price,
106
+ priceImpact: quote.priceImpact,
107
+ transactionData: { tokenApproval, permit2Approval, swap: swapTx },
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Get a price quote for a swap pair.
113
+ * @param params - Price query with assets, optional amounts, and chain
114
+ * @returns Quote with price, amounts, price impact, and route
115
+ */
116
+ protected async _getPrice(params: SwapPriceParams): Promise<SwapPrice> {
117
+ const { chainId, assetIn, assetOut } = params
118
+ const addresses = getUniswapAddresses(chainId)
119
+ const publicClient = this.chainManager.getPublicClient(chainId)
120
+
121
+ if (!assetOut) {
122
+ throw new Error('assetOut is required')
123
+ }
124
+
125
+ const marketConfig = this.resolveUniswapConfig(assetIn, assetOut, chainId)
126
+
127
+ // Default to 1 unit for price quotes when no amount specified
128
+ const amountInWei = parseAssetAmount(assetIn, params.amountIn ?? 1)
129
+ const amountOutWei = parseAssetAmount(assetOut, params.amountOut)
130
+
131
+ return getQuote({
132
+ assetIn,
133
+ assetOut,
134
+ amountInWei: amountOutWei ? undefined : amountInWei,
135
+ amountOutWei,
136
+ chainId,
137
+ publicClient,
138
+ quoterAddress: addresses.quoter,
139
+ poolManagerAddress: addresses.poolManager,
140
+ fee: marketConfig.fee,
141
+ tickSpacing: marketConfig.tickSpacing,
142
+ })
143
+ }
144
+
145
+ /**
146
+ * Find a specific market by poolId from the allowlist.
147
+ * @param params - Pool ID and chain to look up
148
+ * @returns Matching market
149
+ * @throws If no matching market found in config
150
+ */
151
+ protected async _getMarket(params: GetSwapMarketParams): Promise<SwapMarket> {
152
+ const { poolId, chainId } = params
153
+
154
+ for (const config of this.validConfigs()) {
155
+ if (config.chainId !== undefined && config.chainId !== chainId) continue
156
+ const match = this.marketsFromConfig(config, chainId).find(
157
+ (m) => m.marketId.poolId === poolId,
158
+ )
159
+ if (match) return match
160
+ }
161
+
162
+ throw new Error(
163
+ `Market with poolId ${poolId} not found on chain ${chainId}`,
164
+ )
165
+ }
166
+
167
+ /**
168
+ * Expand the market allowlist into concrete SwapMarket objects.
169
+ * Derives poolId from each asset pair's pool key — no RPC calls needed.
170
+ * @param params - Optional chain and asset filters
171
+ * @returns All configured markets matching the filters
172
+ */
173
+ protected async _getMarkets(
174
+ params: GetSwapMarketsParams,
175
+ ): Promise<SwapMarket[]> {
176
+ return this.validConfigs().flatMap((config) => {
177
+ const chainIds = params.chainId
178
+ ? [params.chainId]
179
+ : config.chainId
180
+ ? [config.chainId]
181
+ : this.supportedChainIds()
182
+
183
+ return chainIds.flatMap((chainId) =>
184
+ this.marketsFromConfig(config, chainId, params.asset),
185
+ )
186
+ })
187
+ }
188
+
189
+ // ─────────────────────────────────────────────────────────────────────────────
190
+ // Private helpers
191
+ // ─────────────────────────────────────────────────────────────────────────────
192
+
193
+ /**
194
+ * Look up the Uniswap-specific market config for a pair, validating fee/tickSpacing.
195
+ * @param assetIn - Input asset
196
+ * @param assetOut - Output asset
197
+ * @param chainId - Target chain
198
+ * @returns Market config with guaranteed fee and tickSpacing
199
+ * @throws If pair not in allowlist or missing fee/tickSpacing
200
+ */
201
+ private resolveUniswapConfig(
202
+ assetIn: Asset,
203
+ assetOut: Asset,
204
+ chainId: SupportedChainId,
205
+ ): UniswapMarketConfig & { fee: number; tickSpacing: number } {
206
+ const config = this.resolveMarketConfig(assetIn, assetOut, chainId) as
207
+ | UniswapMarketConfig
208
+ | undefined
209
+ if (config?.fee === undefined || config?.tickSpacing === undefined) {
210
+ throw new Error(
211
+ `fee and tickSpacing must be configured for pair ${assetIn.metadata.symbol}/${assetOut.metadata.symbol}`,
212
+ )
213
+ }
214
+ return config as UniswapMarketConfig & { fee: number; tickSpacing: number }
215
+ }
216
+
217
+ /** @returns Allowlist entries that have the required fee and tickSpacing set */
218
+ private validConfigs(): Array<
219
+ UniswapMarketConfig & { fee: number; tickSpacing: number }
220
+ > {
221
+ return (this._config.marketAllowlist ?? []).filter(
222
+ (f): f is UniswapMarketConfig & { fee: number; tickSpacing: number } =>
223
+ f.fee !== undefined && f.tickSpacing !== undefined,
224
+ )
225
+ }
226
+
227
+ /**
228
+ * Generate all SwapMarket objects from a single config entry on a given chain.
229
+ * @param config - Market config with fee/tickSpacing
230
+ * @param chainId - Target chain
231
+ * @param asset - If provided, only return markets containing this asset
232
+ */
233
+ private marketsFromConfig(
234
+ config: UniswapMarketConfig & { fee: number; tickSpacing: number },
235
+ chainId: SupportedChainId,
236
+ asset?: Asset,
237
+ ): SwapMarket[] {
238
+ return this.assetPairs(config.assets, asset)
239
+ .map(([a, b]) =>
240
+ this.configToMarket(a, b, chainId, config.fee, config.tickSpacing),
241
+ )
242
+ .filter((m): m is SwapMarket => m !== null)
243
+ }
244
+
245
+ /**
246
+ * Generate unique asset pairs, optionally scoped to pairs containing a required asset.
247
+ * @param assets - Full list of assets from a market config
248
+ * @param requiredAsset - If set, only pairs including this asset are returned
249
+ */
250
+ private assetPairs(
251
+ assets: Asset[],
252
+ requiredAsset?: Asset,
253
+ ): Array<[Asset, Asset]> {
254
+ return assets
255
+ .flatMap((a, i) => assets.slice(i + 1).map((b): [Asset, Asset] => [a, b]))
256
+ .filter(
257
+ ([a, b]) =>
258
+ !requiredAsset || a === requiredAsset || b === requiredAsset,
259
+ )
260
+ }
261
+
262
+ /**
263
+ * Build a SwapMarket from two assets and V4 pool parameters.
264
+ * Computes a deterministic poolId from the sorted pool key.
265
+ * @returns SwapMarket, or null if either asset lacks an address on this chain
266
+ */
267
+ private configToMarket(
268
+ assetA: Asset,
269
+ assetB: Asset,
270
+ chainId: SupportedChainId,
271
+ fee: number,
272
+ tickSpacing: number,
273
+ ): SwapMarket | null {
274
+ const addrA = assetA.address[chainId]
275
+ const addrB = assetB.address[chainId]
276
+ if (!addrA || addrA === 'native' || !addrB || addrB === 'native')
277
+ return null
278
+
279
+ // V4 requires currency0 < currency1 for deterministic pool keys
280
+ const [currency0, currency1] =
281
+ addrA.toLowerCase() < addrB.toLowerCase()
282
+ ? [addrA, addrB]
283
+ : [addrB, addrA]
284
+
285
+ // PoolId = keccak256(abi.encode(PoolKey)) per V4's PoolIdLibrary
286
+ // @see https://github.com/Uniswap/v4-core/blob/main/src/types/PoolId.sol
287
+ const poolId = keccak256(
288
+ encodeAbiParameters(POOL_KEY_ABI_TYPE, [
289
+ currency0 as Address,
290
+ currency1 as Address,
291
+ fee,
292
+ tickSpacing,
293
+ '0x0000000000000000000000000000000000000000' as Address,
294
+ ]),
295
+ )
296
+
297
+ return {
298
+ marketId: { poolId, chainId },
299
+ assets: [assetA, assetB],
300
+ fee,
301
+ provider: 'uniswap',
302
+ }
303
+ }
304
+ }