@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.
- package/dist/__mocks__/MockAssets.d.ts.map +1 -1
- package/dist/__mocks__/MockAssets.js +2 -0
- package/dist/__mocks__/MockAssets.js.map +1 -1
- package/dist/__tests__/actions.test.js +0 -4
- package/dist/__tests__/actions.test.js.map +1 -1
- package/dist/actions.d.ts +20 -1
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +37 -13
- package/dist/actions.js.map +1 -1
- package/dist/constants/assets.d.ts +4 -0
- package/dist/constants/assets.d.ts.map +1 -1
- package/dist/constants/assets.js +15 -0
- package/dist/constants/assets.js.map +1 -1
- package/dist/constants/contracts.d.ts +4 -0
- package/dist/constants/contracts.d.ts.map +1 -0
- package/dist/constants/contracts.js +3 -0
- package/dist/constants/contracts.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lend/core/LendProvider.d.ts +0 -6
- package/dist/lend/core/LendProvider.d.ts.map +1 -1
- package/dist/lend/core/LendProvider.js +6 -15
- package/dist/lend/core/LendProvider.js.map +1 -1
- package/dist/lend/core/__tests__/LendProvider.test.js +2 -4
- package/dist/lend/core/__tests__/LendProvider.test.js.map +1 -1
- package/dist/lend/providers/morpho/__tests__/sdk.test.js +3 -2
- package/dist/lend/providers/morpho/__tests__/sdk.test.js.map +1 -1
- package/dist/lend/providers/morpho/api.d.ts +4 -0
- package/dist/lend/providers/morpho/api.d.ts.map +1 -1
- package/dist/lend/providers/morpho/api.js.map +1 -1
- package/dist/lend/providers/morpho/sdk.d.ts.map +1 -1
- package/dist/lend/providers/morpho/sdk.js +10 -1
- package/dist/lend/providers/morpho/sdk.js.map +1 -1
- package/dist/supported/tokens.d.ts.map +1 -1
- package/dist/supported/tokens.js +9 -2
- package/dist/supported/tokens.js.map +1 -1
- package/dist/swap/__mocks__/MockSwapProvider.d.ts +38 -0
- package/dist/swap/__mocks__/MockSwapProvider.d.ts.map +1 -0
- package/dist/swap/__mocks__/MockSwapProvider.js +138 -0
- package/dist/swap/__mocks__/MockSwapProvider.js.map +1 -0
- package/dist/swap/core/SwapProvider.d.ts +56 -0
- package/dist/swap/core/SwapProvider.d.ts.map +1 -0
- package/dist/swap/core/SwapProvider.js +177 -0
- package/dist/swap/core/SwapProvider.js.map +1 -0
- package/dist/swap/core/__tests__/SwapProvider.test.d.ts +2 -0
- package/dist/swap/core/__tests__/SwapProvider.test.d.ts.map +1 -0
- package/dist/swap/core/__tests__/SwapProvider.test.js +329 -0
- package/dist/swap/core/__tests__/SwapProvider.test.js.map +1 -0
- package/dist/swap/index.d.ts +7 -0
- package/dist/swap/index.d.ts.map +1 -0
- package/dist/swap/index.js +8 -0
- package/dist/swap/index.js.map +1 -0
- package/dist/swap/namespaces/ActionsSwapNamespace.d.ts +8 -0
- package/dist/swap/namespaces/ActionsSwapNamespace.d.ts.map +1 -0
- package/dist/swap/namespaces/ActionsSwapNamespace.js +8 -0
- package/dist/swap/namespaces/ActionsSwapNamespace.js.map +1 -0
- package/dist/swap/namespaces/BaseSwapNamespace.d.ts +33 -0
- package/dist/swap/namespaces/BaseSwapNamespace.d.ts.map +1 -0
- package/dist/swap/namespaces/BaseSwapNamespace.js +58 -0
- package/dist/swap/namespaces/BaseSwapNamespace.js.map +1 -0
- package/dist/swap/namespaces/WalletSwapNamespace.d.ts +22 -0
- package/dist/swap/namespaces/WalletSwapNamespace.d.ts.map +1 -0
- package/dist/swap/namespaces/WalletSwapNamespace.js +60 -0
- package/dist/swap/namespaces/WalletSwapNamespace.js.map +1 -0
- package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.d.ts +2 -0
- package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.d.ts.map +1 -0
- package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.js +106 -0
- package/dist/swap/namespaces/__tests__/BaseSwapNamespace.spec.js.map +1 -0
- package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.d.ts +2 -0
- package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.d.ts.map +1 -0
- package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.js +132 -0
- package/dist/swap/namespaces/__tests__/WalletSwapNamespace.spec.js.map +1 -0
- package/dist/swap/providers/uniswap/UniswapSwapProvider.d.ts +68 -0
- package/dist/swap/providers/uniswap/UniswapSwapProvider.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/UniswapSwapProvider.js +206 -0
- package/dist/swap/providers/uniswap/UniswapSwapProvider.js.map +1 -0
- package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.d.ts +2 -0
- package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.js +257 -0
- package/dist/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.js.map +1 -0
- package/dist/swap/providers/uniswap/__tests__/sdk.test.d.ts +2 -0
- package/dist/swap/providers/uniswap/__tests__/sdk.test.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/__tests__/sdk.test.js +312 -0
- package/dist/swap/providers/uniswap/__tests__/sdk.test.js.map +1 -0
- package/dist/swap/providers/uniswap/abis.d.ts +227 -0
- package/dist/swap/providers/uniswap/abis.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/abis.js +138 -0
- package/dist/swap/providers/uniswap/abis.js.map +1 -0
- package/dist/swap/providers/uniswap/addresses.d.ts +21 -0
- package/dist/swap/providers/uniswap/addresses.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/addresses.js +81 -0
- package/dist/swap/providers/uniswap/addresses.js.map +1 -0
- package/dist/swap/providers/uniswap/encoding.d.ts +77 -0
- package/dist/swap/providers/uniswap/encoding.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/encoding.js +233 -0
- package/dist/swap/providers/uniswap/encoding.js.map +1 -0
- package/dist/swap/providers/uniswap/types.d.ts +20 -0
- package/dist/swap/providers/uniswap/types.d.ts.map +1 -0
- package/dist/swap/providers/uniswap/types.js +2 -0
- package/dist/swap/providers/uniswap/types.js.map +1 -0
- package/dist/types/actions.d.ts +19 -5
- package/dist/types/actions.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/lend/base.d.ts +3 -13
- package/dist/types/lend/base.d.ts.map +1 -1
- package/dist/types/lend/base.js.map +1 -1
- package/dist/types/swap/base.d.ts +238 -0
- package/dist/types/swap/base.d.ts.map +1 -0
- package/dist/types/swap/base.js +4 -0
- package/dist/types/swap/base.js.map +1 -0
- package/dist/types/swap/index.d.ts +2 -0
- package/dist/types/swap/index.d.ts.map +1 -0
- package/dist/types/swap/index.js +2 -0
- package/dist/types/swap/index.js.map +1 -0
- package/dist/types/transaction.d.ts +14 -0
- package/dist/types/transaction.d.ts.map +1 -0
- package/dist/types/transaction.js +2 -0
- package/dist/types/transaction.js.map +1 -0
- package/dist/utils/assets.d.ts +4 -5
- package/dist/utils/assets.d.ts.map +1 -1
- package/dist/utils/assets.js +4 -11
- package/dist/utils/assets.js.map +1 -1
- package/dist/utils/assets.test.js +13 -1
- package/dist/utils/assets.test.js.map +1 -1
- package/dist/utils/permit2.d.ts +46 -0
- package/dist/utils/permit2.d.ts.map +1 -0
- package/dist/utils/permit2.js +100 -0
- package/dist/utils/permit2.js.map +1 -0
- package/dist/utils/permit2.test.d.ts +2 -0
- package/dist/utils/permit2.test.d.ts.map +1 -0
- package/dist/utils/permit2.test.js +110 -0
- package/dist/utils/permit2.test.js.map +1 -0
- package/dist/utils/validation.d.ts +12 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +44 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts +7 -1
- package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js +2 -1
- package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js.map +1 -1
- package/dist/wallet/core/providers/hosted/types/index.d.ts +5 -1
- package/dist/wallet/core/providers/hosted/types/index.d.ts.map +1 -1
- package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts +7 -1
- package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts.map +1 -1
- package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js +5 -1
- package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js.map +1 -1
- package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js +2 -2
- package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js.map +1 -1
- package/dist/wallet/core/wallets/abstract/Wallet.d.ts +13 -2
- package/dist/wallet/core/wallets/abstract/Wallet.d.ts.map +1 -1
- package/dist/wallet/core/wallets/abstract/Wallet.js +7 -1
- package/dist/wallet/core/wallets/abstract/Wallet.js.map +1 -1
- package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts +7 -2
- package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts.map +1 -1
- package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js +6 -5
- package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js.map +1 -1
- package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +6 -1
- package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js +3 -1
- package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
- package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.d.ts.map +1 -1
- package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js +4 -3
- package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js.map +1 -1
- package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +5 -1
- package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +4 -2
- package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
- package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts +6 -1
- package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
- package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js +4 -3
- package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js.map +1 -1
- package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts +5 -1
- package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
- package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
- package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
- package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts +7 -1
- package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js +6 -2
- package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js.map +1 -1
- package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js +1 -0
- package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js.map +1 -1
- package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +6 -1
- package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js +5 -2
- package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
- package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js +1 -0
- package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js.map +1 -1
- package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +6 -3
- package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
- package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +5 -4
- package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
- package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.d.ts.map +1 -1
- package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js +6 -6
- package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js.map +1 -1
- package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts +7 -1
- package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts.map +1 -1
- package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js +5 -3
- package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js.map +1 -1
- package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts +5 -1
- package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
- package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js +3 -3
- package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js.map +1 -1
- package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts +5 -1
- package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
- package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
- package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
- package/package.json +2 -2
- package/src/__mocks__/MockAssets.ts +2 -0
- package/src/__tests__/actions.test.ts +0 -4
- package/src/actions.ts +57 -19
- package/src/constants/assets.ts +16 -0
- package/src/constants/contracts.ts +5 -0
- package/src/index.ts +30 -2
- package/src/lend/core/LendProvider.ts +6 -18
- package/src/lend/core/__tests__/LendProvider.test.ts +2 -5
- package/src/lend/providers/morpho/__tests__/sdk.test.ts +3 -2
- package/src/lend/providers/morpho/api.ts +4 -0
- package/src/lend/providers/morpho/sdk.ts +10 -1
- package/src/supported/tokens.ts +16 -2
- package/src/swap/__mocks__/MockSwapProvider.ts +216 -0
- package/src/swap/core/SwapProvider.ts +319 -0
- package/src/swap/core/__tests__/SwapProvider.test.ts +478 -0
- package/src/swap/index.ts +14 -0
- package/src/swap/namespaces/ActionsSwapNamespace.ts +7 -0
- package/src/swap/namespaces/BaseSwapNamespace.ts +77 -0
- package/src/swap/namespaces/WalletSwapNamespace.ts +82 -0
- package/src/swap/namespaces/__tests__/BaseSwapNamespace.spec.ts +138 -0
- package/src/swap/namespaces/__tests__/WalletSwapNamespace.spec.ts +162 -0
- package/src/swap/providers/uniswap/UniswapSwapProvider.ts +304 -0
- package/src/swap/providers/uniswap/__tests__/UniswapSwapProvider.test.ts +299 -0
- package/src/swap/providers/uniswap/__tests__/sdk.test.ts +370 -0
- package/src/swap/providers/uniswap/abis.ts +144 -0
- package/src/swap/providers/uniswap/addresses.ts +108 -0
- package/src/swap/providers/uniswap/encoding.ts +406 -0
- package/src/swap/providers/uniswap/types.ts +24 -0
- package/src/types/actions.ts +22 -6
- package/src/types/index.ts +2 -0
- package/src/types/lend/base.ts +4 -14
- package/src/types/swap/base.ts +259 -0
- package/src/types/swap/index.ts +1 -0
- package/src/types/transaction.ts +14 -0
- package/src/utils/assets.test.ts +16 -1
- package/src/utils/assets.ts +13 -10
- package/src/utils/permit2.test.ts +142 -0
- package/src/utils/permit2.ts +144 -0
- package/src/utils/validation.ts +76 -0
- package/src/wallet/core/providers/hosted/abstract/HostedWalletProvider.ts +9 -1
- package/src/wallet/core/providers/hosted/types/index.ts +5 -1
- package/src/wallet/core/providers/smart/default/DefaultSmartWalletProvider.ts +13 -1
- package/src/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.ts +2 -0
- package/src/wallet/core/wallets/abstract/Wallet.ts +18 -2
- package/src/wallet/core/wallets/smart/default/DefaultSmartWallet.ts +14 -5
- package/src/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.ts +13 -2
- package/src/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.ts +10 -2
- package/src/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +8 -2
- package/src/wallet/node/wallets/hosted/privy/PrivyWallet.ts +11 -2
- package/src/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.ts +10 -2
- package/src/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.ts +10 -2
- package/src/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.ts +1 -0
- package/src/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.ts +9 -2
- package/src/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.ts +1 -0
- package/src/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +9 -4
- package/src/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.ts +18 -6
- package/src/wallet/react/wallets/hosted/dynamic/DynamicWallet.ts +12 -2
- package/src/wallet/react/wallets/hosted/privy/PrivyWallet.ts +10 -2
- 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
|
+
}
|