@eth-optimism/actions-sdk 0.0.4 → 0.1.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 (201) hide show
  1. package/dist/actions.d.ts +19 -7
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +49 -19
  4. package/dist/actions.js.map +1 -1
  5. package/dist/actions.test.js +30 -80
  6. package/dist/actions.test.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/lend/core/LendProvider.d.ts +3 -2
  11. package/dist/lend/core/LendProvider.d.ts.map +1 -1
  12. package/dist/lend/core/LendProvider.js.map +1 -1
  13. package/dist/lend/core/__tests__/LendProvider.test.js +18 -48
  14. package/dist/lend/core/__tests__/LendProvider.test.js.map +1 -1
  15. package/dist/lend/index.d.ts +1 -0
  16. package/dist/lend/index.d.ts.map +1 -1
  17. package/dist/lend/index.js +1 -0
  18. package/dist/lend/index.js.map +1 -1
  19. package/dist/lend/namespaces/ActionsLendNamespace.d.ts +35 -8
  20. package/dist/lend/namespaces/ActionsLendNamespace.d.ts.map +1 -1
  21. package/dist/lend/namespaces/ActionsLendNamespace.js +45 -8
  22. package/dist/lend/namespaces/ActionsLendNamespace.js.map +1 -1
  23. package/dist/lend/namespaces/WalletLendNamespace.d.ts +35 -8
  24. package/dist/lend/namespaces/WalletLendNamespace.d.ts.map +1 -1
  25. package/dist/lend/namespaces/WalletLendNamespace.js +59 -11
  26. package/dist/lend/namespaces/WalletLendNamespace.js.map +1 -1
  27. package/dist/lend/namespaces/__tests__/ActionsLendNamespace.spec.js +23 -15
  28. package/dist/lend/namespaces/__tests__/ActionsLendNamespace.spec.js.map +1 -1
  29. package/dist/lend/namespaces/__tests__/WalletLendNamespace.spec.js +29 -11
  30. package/dist/lend/namespaces/__tests__/WalletLendNamespace.spec.js.map +1 -1
  31. package/dist/lend/providers/aave/AaveLendProvider.d.ts +82 -0
  32. package/dist/lend/providers/aave/AaveLendProvider.d.ts.map +1 -0
  33. package/dist/lend/providers/aave/AaveLendProvider.js +346 -0
  34. package/dist/lend/providers/aave/AaveLendProvider.js.map +1 -0
  35. package/dist/lend/providers/aave/addresses.d.ts +57 -0
  36. package/dist/lend/providers/aave/addresses.d.ts.map +1 -0
  37. package/dist/lend/providers/aave/addresses.js +83 -0
  38. package/dist/lend/providers/aave/addresses.js.map +1 -0
  39. package/dist/lend/providers/aave/sdk.d.ts +57 -0
  40. package/dist/lend/providers/aave/sdk.d.ts.map +1 -0
  41. package/dist/lend/providers/aave/sdk.js +260 -0
  42. package/dist/lend/providers/aave/sdk.js.map +1 -0
  43. package/dist/lend/providers/morpho/MorphoLendProvider.d.ts +4 -3
  44. package/dist/lend/providers/morpho/MorphoLendProvider.d.ts.map +1 -1
  45. package/dist/lend/providers/morpho/MorphoLendProvider.js +2 -2
  46. package/dist/lend/providers/morpho/MorphoLendProvider.js.map +1 -1
  47. package/dist/lend/providers/morpho/__tests__/MorphoLendProvider.test.js +1 -33
  48. package/dist/lend/providers/morpho/__tests__/MorphoLendProvider.test.js.map +1 -1
  49. package/dist/lend/providers/morpho/__tests__/sdk.test.js +1 -0
  50. package/dist/lend/providers/morpho/__tests__/sdk.test.js.map +1 -1
  51. package/dist/lend/providers/morpho/sdk.d.ts +4 -3
  52. package/dist/lend/providers/morpho/sdk.d.ts.map +1 -1
  53. package/dist/supported/tokens.d.ts.map +1 -1
  54. package/dist/supported/tokens.js +18 -2
  55. package/dist/supported/tokens.js.map +1 -1
  56. package/dist/test/MockLendProvider.d.ts +5 -4
  57. package/dist/test/MockLendProvider.d.ts.map +1 -1
  58. package/dist/test/MockLendProvider.js +5 -5
  59. package/dist/test/MockLendProvider.js.map +1 -1
  60. package/dist/types/actions.d.ts +26 -2
  61. package/dist/types/actions.d.ts.map +1 -1
  62. package/dist/types/lend/base.d.ts +6 -19
  63. package/dist/types/lend/base.d.ts.map +1 -1
  64. package/dist/wallet/core/namespace/__tests__/WalletNamespace.spec.js +9 -9
  65. package/dist/wallet/core/namespace/__tests__/WalletNamespace.spec.js.map +1 -1
  66. package/dist/wallet/core/providers/__tests__/WalletProvider.spec.js +8 -8
  67. package/dist/wallet/core/providers/__tests__/WalletProvider.spec.js.map +1 -1
  68. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts +12 -3
  69. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.d.ts.map +1 -1
  70. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js +3 -2
  71. package/dist/wallet/core/providers/hosted/abstract/HostedWalletProvider.js.map +1 -1
  72. package/dist/wallet/core/providers/hosted/types/index.d.ts +8 -2
  73. package/dist/wallet/core/providers/hosted/types/index.d.ts.map +1 -1
  74. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts +14 -6
  75. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.d.ts.map +1 -1
  76. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js +10 -6
  77. package/dist/wallet/core/providers/smart/default/DefaultSmartWalletProvider.js.map +1 -1
  78. package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js +36 -13
  79. package/dist/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.js.map +1 -1
  80. package/dist/wallet/core/wallets/abstract/Wallet.d.ts +19 -7
  81. package/dist/wallet/core/wallets/abstract/Wallet.d.ts.map +1 -1
  82. package/dist/wallet/core/wallets/abstract/Wallet.js +9 -7
  83. package/dist/wallet/core/wallets/abstract/Wallet.js.map +1 -1
  84. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts +9 -3
  85. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.d.ts.map +1 -1
  86. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js +4 -4
  87. package/dist/wallet/core/wallets/smart/default/DefaultSmartWallet.js.map +1 -1
  88. package/dist/wallet/core/wallets/smart/default/__tests__/DefaultSmartWallet.spec.js +1 -1
  89. package/dist/wallet/core/wallets/smart/default/__tests__/DefaultSmartWallet.spec.js.map +1 -1
  90. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +10 -3
  91. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
  92. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js +5 -3
  93. package/dist/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
  94. package/dist/wallet/node/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js +4 -3
  95. package/dist/wallet/node/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js.map +1 -1
  96. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.d.ts.map +1 -1
  97. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js +5 -4
  98. package/dist/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.js.map +1 -1
  99. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +9 -2
  100. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
  101. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +6 -3
  102. package/dist/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
  103. package/dist/wallet/node/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.js +4 -3
  104. package/dist/wallet/node/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.js.map +1 -1
  105. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts +10 -3
  106. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
  107. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js +5 -4
  108. package/dist/wallet/node/wallets/hosted/privy/PrivyWallet.js.map +1 -1
  109. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts +8 -2
  110. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
  111. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
  112. package/dist/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
  113. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts +6 -2
  114. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.d.ts.map +1 -1
  115. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js +3 -3
  116. package/dist/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.js.map +1 -1
  117. package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js +19 -7
  118. package/dist/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.js.map +1 -1
  119. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts +6 -2
  120. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.d.ts.map +1 -1
  121. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js +3 -3
  122. package/dist/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.js.map +1 -1
  123. package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js +7 -3
  124. package/dist/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.js.map +1 -1
  125. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts +6 -2
  126. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.d.ts.map +1 -1
  127. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js +3 -3
  128. package/dist/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.js.map +1 -1
  129. package/dist/wallet/react/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.js +6 -3
  130. package/dist/wallet/react/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.js.map +1 -1
  131. package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js +6 -6
  132. package/dist/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.js.map +1 -1
  133. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts +6 -2
  134. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.d.ts.map +1 -1
  135. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js +3 -3
  136. package/dist/wallet/react/wallets/hosted/dynamic/DynamicWallet.js.map +1 -1
  137. package/dist/wallet/react/wallets/hosted/dynamic/__mocks__/DynamicWalletMock.d.ts +6 -0
  138. package/dist/wallet/react/wallets/hosted/dynamic/__mocks__/DynamicWalletMock.d.ts.map +1 -1
  139. package/dist/wallet/react/wallets/hosted/dynamic/__mocks__/DynamicWalletMock.js.map +1 -1
  140. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts +6 -2
  141. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.d.ts.map +1 -1
  142. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js +3 -3
  143. package/dist/wallet/react/wallets/hosted/privy/PrivyWallet.js.map +1 -1
  144. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts +6 -2
  145. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.d.ts.map +1 -1
  146. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js +2 -2
  147. package/dist/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.js.map +1 -1
  148. package/package.json +4 -1
  149. package/src/actions.test.ts +32 -93
  150. package/src/actions.ts +82 -26
  151. package/src/index.ts +1 -2
  152. package/src/lend/core/LendProvider.ts +6 -5
  153. package/src/lend/core/__tests__/LendProvider.test.ts +19 -61
  154. package/src/lend/index.ts +1 -0
  155. package/src/lend/namespaces/ActionsLendNamespace.ts +77 -13
  156. package/src/lend/namespaces/WalletLendNamespace.ts +98 -18
  157. package/src/lend/namespaces/__tests__/ActionsLendNamespace.spec.ts +24 -18
  158. package/src/lend/namespaces/__tests__/WalletLendNamespace.spec.ts +49 -11
  159. package/src/lend/providers/aave/AaveLendProvider.ts +463 -0
  160. package/src/lend/providers/aave/addresses.ts +95 -0
  161. package/src/lend/providers/aave/sdk.ts +369 -0
  162. package/src/lend/providers/morpho/MorphoLendProvider.ts +5 -5
  163. package/src/lend/providers/morpho/__tests__/MorphoLendProvider.test.ts +5 -53
  164. package/src/lend/providers/morpho/__tests__/sdk.test.ts +1 -0
  165. package/src/lend/providers/morpho/sdk.ts +3 -3
  166. package/src/supported/tokens.ts +24 -2
  167. package/src/test/MockLendProvider.ts +9 -9
  168. package/src/types/actions.ts +30 -2
  169. package/src/types/lend/base.ts +6 -22
  170. package/src/wallet/core/namespace/__tests__/WalletNamespace.spec.ts +9 -9
  171. package/src/wallet/core/providers/__tests__/WalletProvider.spec.ts +8 -8
  172. package/src/wallet/core/providers/hosted/abstract/HostedWalletProvider.ts +15 -4
  173. package/src/wallet/core/providers/hosted/types/index.ts +8 -2
  174. package/src/wallet/core/providers/smart/default/DefaultSmartWalletProvider.ts +24 -9
  175. package/src/wallet/core/providers/smart/default/__tests__/DefaultSmartWalletProvider.spec.ts +38 -46
  176. package/src/wallet/core/wallets/abstract/Wallet.ts +25 -17
  177. package/src/wallet/core/wallets/smart/default/DefaultSmartWallet.ts +17 -10
  178. package/src/wallet/core/wallets/smart/default/__tests__/DefaultSmartWallet.spec.ts +4 -7
  179. package/src/wallet/node/providers/hosted/privy/PrivyHostedWalletProvider.ts +13 -5
  180. package/src/wallet/node/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.ts +4 -4
  181. package/src/wallet/node/providers/hosted/registry/NodeHostedWalletProviderRegistry.ts +6 -4
  182. package/src/wallet/node/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +13 -4
  183. package/src/wallet/node/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.ts +4 -4
  184. package/src/wallet/node/wallets/hosted/privy/PrivyWallet.ts +18 -6
  185. package/src/wallet/node/wallets/hosted/turnkey/TurnkeyWallet.ts +16 -5
  186. package/src/wallet/react/providers/hosted/dynamic/DynamicHostedWalletProvider.ts +8 -4
  187. package/src/wallet/react/providers/hosted/dynamic/__tests__/DynamicHostedWalletProvider.spec.ts +25 -14
  188. package/src/wallet/react/providers/hosted/privy/PrivyHostedWalletProvider.ts +8 -4
  189. package/src/wallet/react/providers/hosted/privy/__tests__/PrivyHostedWalletProvider.spec.ts +7 -7
  190. package/src/wallet/react/providers/hosted/turnkey/TurnkeyHostedWalletProvider.ts +8 -4
  191. package/src/wallet/react/providers/hosted/turnkey/__tests__/TurnkeyHostedWalletProvider.spec.ts +6 -7
  192. package/src/wallet/react/providers/registry/ReactHostedWalletProviderRegistry.ts +6 -6
  193. package/src/wallet/react/wallets/hosted/dynamic/DynamicWallet.ts +12 -5
  194. package/src/wallet/react/wallets/hosted/dynamic/__mocks__/DynamicWalletMock.ts +6 -0
  195. package/src/wallet/react/wallets/hosted/privy/PrivyWallet.ts +12 -5
  196. package/src/wallet/react/wallets/hosted/turnkey/TurnkeyWallet.ts +12 -5
  197. package/dist/constants/config.d.ts +0 -10
  198. package/dist/constants/config.d.ts.map +0 -1
  199. package/dist/constants/config.js +0 -10
  200. package/dist/constants/config.js.map +0 -1
  201. package/src/constants/config.ts +0 -9
@@ -0,0 +1,463 @@
1
+ import type { Address } from 'viem'
2
+ import { encodeFunctionData, erc20Abi, formatUnits, parseAbi } from 'viem'
3
+
4
+ import { LendProvider } from '@/lend/core/LendProvider.js'
5
+ import type { ChainManager } from '@/services/ChainManager.js'
6
+ import type { LendProviderConfig } from '@/types/actions.js'
7
+ import type {
8
+ GetLendMarketsParams,
9
+ GetMarketBalanceParams,
10
+ LendClosePositionParams,
11
+ LendMarket,
12
+ LendMarketId,
13
+ LendMarketPosition,
14
+ LendOpenPositionInternalParams,
15
+ LendTransaction,
16
+ } from '@/types/lend/index.js'
17
+ import { getAssetAddress } from '@/utils/assets.js'
18
+
19
+ import {
20
+ getPoolAddress,
21
+ getSupportedChainIds,
22
+ getWETHGatewayAddress,
23
+ } from './addresses.js'
24
+ import { getReserve, getReserves } from './sdk.js'
25
+
26
+ /**
27
+ * WETH predeploy address on OP Stack chains
28
+ * @description WETH is deployed at the same address on all OP Stack chains (Optimism, Base, etc.)
29
+ */
30
+ const WETH_ADDRESS = '0x4200000000000000000000000000000000000006'
31
+
32
+ /**
33
+ * Aave Pool ABI - only the functions we need
34
+ */
35
+ const POOL_ABI = parseAbi([
36
+ 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)',
37
+ 'function withdraw(address asset, uint256 amount, address to) returns (uint256)',
38
+ ])
39
+
40
+ /**
41
+ * Aave WETHGateway ABI - for native ETH deposits/withdrawals
42
+ */
43
+ const WETH_GATEWAY_ABI = parseAbi([
44
+ 'function depositETH(address pool, address onBehalfOf, uint16 referralCode) payable',
45
+ 'function withdrawETH(address pool, uint256 amount, address to)',
46
+ ])
47
+
48
+ /**
49
+ * Supported chain IDs for Aave lending
50
+ * @description Array of chain IDs where Aave V3 is available on Optimism Superchain
51
+ */
52
+ export const SUPPORTED_CHAIN_IDS = getSupportedChainIds() as readonly number[]
53
+
54
+ /**
55
+ * Aave lending provider implementation
56
+ * @description Lending provider implementation using Aave V3 protocol
57
+ */
58
+ export class AaveLendProvider extends LendProvider<LendProviderConfig> {
59
+ protected readonly SUPPORTED_CHAIN_IDS = SUPPORTED_CHAIN_IDS
60
+
61
+ private chainManager: ChainManager
62
+
63
+ /**
64
+ * Create a new Aave lending provider
65
+ * @param config - Aave lending configuration
66
+ * @param chainManager - Chain manager for blockchain interactions
67
+ */
68
+ constructor(config: LendProviderConfig, chainManager: ChainManager) {
69
+ super(config)
70
+ this.chainManager = chainManager
71
+ }
72
+
73
+ /**
74
+ * Check if market is a WETH market
75
+ * @param marketId - Market identifier
76
+ * @returns true if market is for WETH
77
+ * @description WETH is a predeploy at the same address on all OP Stack chains
78
+ */
79
+ private isWETHMarket(marketId: LendMarketId): boolean {
80
+ return marketId.address.toLowerCase() === WETH_ADDRESS.toLowerCase()
81
+ }
82
+
83
+ /**
84
+ * Open a lending position in an Aave market
85
+ * @description Opens a lending position by supplying assets to an Aave reserve
86
+ * @param params - Position opening parameters
87
+ * @returns Promise resolving to lending transaction details
88
+ */
89
+ protected async _openPosition(
90
+ params: LendOpenPositionInternalParams,
91
+ ): Promise<LendTransaction> {
92
+ try {
93
+ // Get Pool address for this chain
94
+ const poolAddress = getPoolAddress(params.marketId.chainId)
95
+ if (!poolAddress) {
96
+ throw new Error(
97
+ `Aave V3 not deployed on chain ${params.marketId.chainId}`,
98
+ )
99
+ }
100
+
101
+ // Get market information for APY
102
+ const marketInfo = await this.getMarket({
103
+ address: params.marketId.address,
104
+ chainId: params.marketId.chainId,
105
+ })
106
+
107
+ // Check if this is a WETH market
108
+ if (this.isWETHMarket(params.marketId)) {
109
+ return this._openWETHPosition(params, poolAddress, marketInfo)
110
+ }
111
+
112
+ // Standard ERC-20 flow
113
+ return this._openERC20Position(params, poolAddress, marketInfo)
114
+ } catch (error) {
115
+ throw new Error(
116
+ `Failed to open position with ${params.amountWei} of ${params.asset.metadata.symbol}: ${
117
+ error instanceof Error ? error.message : 'Unknown error'
118
+ }`,
119
+ )
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Open position for WETH market using WETHGateway
125
+ * @description Deposits native ETH via WETHGateway which wraps and deposits in one tx
126
+ */
127
+ private async _openWETHPosition(
128
+ params: LendOpenPositionInternalParams,
129
+ poolAddress: Address,
130
+ marketInfo: LendMarket,
131
+ ): Promise<LendTransaction> {
132
+ const gatewayAddress = getWETHGatewayAddress(params.marketId.chainId)
133
+ if (!gatewayAddress) {
134
+ throw new Error(
135
+ `WETHGateway not available on chain ${params.marketId.chainId}`,
136
+ )
137
+ }
138
+
139
+ // Generate depositETH transaction
140
+ const depositCallData = encodeFunctionData({
141
+ abi: WETH_GATEWAY_ABI,
142
+ functionName: 'depositETH',
143
+ args: [
144
+ poolAddress, // pool address
145
+ params.walletAddress, // onBehalfOf (receives aWETH)
146
+ 0, // referralCode (0 = no referral)
147
+ ],
148
+ })
149
+
150
+ return {
151
+ amount: params.amountWei,
152
+ asset: WETH_ADDRESS,
153
+ marketId: params.marketId.address,
154
+ apy: marketInfo.apy.total,
155
+ transactionData: {
156
+ openPosition: {
157
+ to: gatewayAddress,
158
+ data: depositCallData,
159
+ value: params.amountWei, // Send ETH as msg.value
160
+ },
161
+ },
162
+ slippage: params.options?.slippage ?? 50,
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Open position for standard ERC-20 tokens
168
+ * @description Standard approve + supply flow for non-WETH assets
169
+ */
170
+ private async _openERC20Position(
171
+ params: LendOpenPositionInternalParams,
172
+ poolAddress: Address,
173
+ marketInfo: LendMarket,
174
+ ): Promise<LendTransaction> {
175
+ // Get asset address for the chain
176
+ const assetAddress = params.asset.address[params.marketId.chainId]
177
+ if (!assetAddress) {
178
+ throw new Error(`Asset not supported on chain ${params.marketId.chainId}`)
179
+ }
180
+
181
+ // Generate approval transaction
182
+ const approvalCallData = encodeFunctionData({
183
+ abi: erc20Abi,
184
+ functionName: 'approve',
185
+ args: [poolAddress, params.amountWei],
186
+ })
187
+
188
+ // Generate supply transaction
189
+ const supplyCallData = encodeFunctionData({
190
+ abi: POOL_ABI,
191
+ functionName: 'supply',
192
+ args: [
193
+ assetAddress, // asset
194
+ params.amountWei, // amount
195
+ params.walletAddress, // onBehalfOf
196
+ 0, // referralCode
197
+ ],
198
+ })
199
+
200
+ return {
201
+ amount: params.amountWei,
202
+ asset: assetAddress,
203
+ marketId: params.marketId.address,
204
+ apy: marketInfo.apy.total,
205
+ transactionData: {
206
+ approval: {
207
+ to: assetAddress,
208
+ data: approvalCallData,
209
+ value: 0n,
210
+ },
211
+ openPosition: {
212
+ to: poolAddress,
213
+ data: supplyCallData,
214
+ value: 0n,
215
+ },
216
+ },
217
+ slippage: params.options?.slippage ?? 50,
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Close a position in an Aave market
223
+ * @description Withdraws assets from an Aave reserve
224
+ * @param params - Position closing operation parameters
225
+ * @returns Promise resolving to withdrawal transaction details
226
+ */
227
+ protected async _closePosition(
228
+ params: LendClosePositionParams,
229
+ ): Promise<LendTransaction> {
230
+ try {
231
+ // Get Pool address for this chain
232
+ const poolAddress = getPoolAddress(params.marketId.chainId)
233
+ if (!poolAddress) {
234
+ throw new Error(
235
+ `Aave V3 not deployed on chain ${params.marketId.chainId}`,
236
+ )
237
+ }
238
+
239
+ const marketInfo = await this.getMarket({
240
+ address: params.marketId.address,
241
+ chainId: params.marketId.chainId,
242
+ })
243
+
244
+ // Check if this is a WETH market
245
+ if (this.isWETHMarket(params.marketId)) {
246
+ return this._closeWETHPosition(params, poolAddress, marketInfo)
247
+ }
248
+
249
+ // Standard ERC-20 flow
250
+ return this._closeERC20Position(params, poolAddress, marketInfo)
251
+ } catch (error) {
252
+ throw new Error(
253
+ `Failed to close position: ${
254
+ error instanceof Error ? error.message : 'Unknown error'
255
+ }`,
256
+ )
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Close position for WETH market using WETHGateway
262
+ * @description Withdraws aWETH, unwraps to ETH, and sends to user
263
+ */
264
+ private async _closeWETHPosition(
265
+ params: LendClosePositionParams,
266
+ poolAddress: Address,
267
+ marketInfo: LendMarket,
268
+ ): Promise<LendTransaction> {
269
+ const gatewayAddress = getWETHGatewayAddress(params.marketId.chainId)
270
+ if (!gatewayAddress) {
271
+ throw new Error(
272
+ `WETHGateway not available on chain ${params.marketId.chainId}`,
273
+ )
274
+ }
275
+
276
+ // Get the aToken address for the underlying WETH asset
277
+ // Note: params.marketId.address is the underlying WETH address, not the aToken
278
+ const { getATokenAddress } = await import('./sdk.js')
279
+ const aWETHAddress = await getATokenAddress({
280
+ underlyingAsset: params.marketId.address,
281
+ chainId: params.marketId.chainId,
282
+ chainManager: this.chainManager,
283
+ })
284
+
285
+ // First: User must approve aWETH to WETHGateway
286
+ const approvalCallData = encodeFunctionData({
287
+ abi: erc20Abi,
288
+ functionName: 'approve',
289
+ args: [gatewayAddress, params.amount],
290
+ })
291
+
292
+ // Second: Call withdrawETH on gateway
293
+ const withdrawCallData = encodeFunctionData({
294
+ abi: WETH_GATEWAY_ABI,
295
+ functionName: 'withdrawETH',
296
+ args: [
297
+ poolAddress, // pool
298
+ params.amount, // amount
299
+ params.walletAddress, // to (receives native ETH)
300
+ ],
301
+ })
302
+
303
+ return {
304
+ amount: params.amount,
305
+ asset: WETH_ADDRESS,
306
+ marketId: params.marketId.address,
307
+ apy: marketInfo.apy.total,
308
+ transactionData: {
309
+ approval: {
310
+ to: aWETHAddress,
311
+ data: approvalCallData,
312
+ value: 0n,
313
+ },
314
+ closePosition: {
315
+ to: gatewayAddress,
316
+ data: withdrawCallData,
317
+ value: 0n,
318
+ },
319
+ },
320
+ slippage: params.options?.slippage ?? 50,
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Close position for standard ERC-20 tokens
326
+ */
327
+ private async _closeERC20Position(
328
+ params: LendClosePositionParams,
329
+ poolAddress: Address,
330
+ marketInfo: LendMarket,
331
+ ): Promise<LendTransaction> {
332
+ // Get asset address for the market's chain
333
+ const assetAddress = getAssetAddress(
334
+ marketInfo.asset,
335
+ params.marketId.chainId,
336
+ )
337
+
338
+ // Generate withdraw transaction
339
+ const withdrawCallData = encodeFunctionData({
340
+ abi: POOL_ABI,
341
+ functionName: 'withdraw',
342
+ args: [
343
+ assetAddress, // asset
344
+ params.amount, // amount
345
+ params.walletAddress, // to
346
+ ],
347
+ })
348
+
349
+ return {
350
+ amount: params.amount,
351
+ asset: assetAddress,
352
+ marketId: params.marketId.address,
353
+ apy: marketInfo.apy.total,
354
+ transactionData: {
355
+ closePosition: {
356
+ to: poolAddress,
357
+ data: withdrawCallData,
358
+ value: 0n,
359
+ },
360
+ },
361
+ slippage: params.options?.slippage ?? 50,
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Get detailed market information
367
+ * @param marketId - Market identifier containing address and chainId
368
+ * @returns Promise resolving to market information
369
+ */
370
+ protected async _getMarket(marketId: LendMarketId): Promise<LendMarket> {
371
+ return getReserve({
372
+ marketId,
373
+ chainManager: this.chainManager,
374
+ lendConfig: this._config,
375
+ })
376
+ }
377
+
378
+ /**
379
+ * Get list of available lending markets
380
+ * @param params - Filtering parameters
381
+ * @returns Promise resolving to array of market information
382
+ */
383
+ protected async _getMarkets(
384
+ params: GetLendMarketsParams,
385
+ ): Promise<LendMarket[]> {
386
+ const marketConfigs = params.markets || []
387
+
388
+ return getReserves({
389
+ chainManager: this.chainManager,
390
+ lendConfig: this._config,
391
+ markets: marketConfigs,
392
+ })
393
+ }
394
+
395
+ /**
396
+ * Get position for a specific wallet address
397
+ * @param params - Parameters for fetching position
398
+ * @returns Promise resolving to position information
399
+ */
400
+ protected async _getPosition(
401
+ params: GetMarketBalanceParams,
402
+ ): Promise<LendMarketPosition> {
403
+ try {
404
+ const publicClient = this.chainManager.getPublicClient(
405
+ params.marketId.chainId,
406
+ )
407
+ const market = await this._getMarket(params.marketId)
408
+ const poolAddress = getPoolAddress(params.marketId.chainId)
409
+
410
+ if (!poolAddress) {
411
+ throw new Error(
412
+ `Aave V3 not deployed on chain ${params.marketId.chainId}`,
413
+ )
414
+ }
415
+
416
+ // Get the aToken address from Pool.getReserveData
417
+ const assetAddress = getAssetAddress(
418
+ market.asset,
419
+ params.marketId.chainId,
420
+ )
421
+
422
+ const reserveData = (await publicClient.readContract({
423
+ address: poolAddress,
424
+ abi: parseAbi([
425
+ 'struct ReserveData { uint256 configuration; uint128 liquidityIndex; uint128 currentLiquidityRate; uint128 variableBorrowIndex; uint128 currentVariableBorrowRate; uint128 currentStableBorrowRate; uint40 lastUpdateTimestamp; uint16 id; address aTokenAddress; address stableDebtTokenAddress; address variableDebtTokenAddress; address interestRateStrategyAddress; uint128 accruedToTreasury; uint128 unbacked; uint128 isolationModeTotalDebt; }',
426
+ 'function getReserveData(address asset) view returns (ReserveData)',
427
+ ]),
428
+ functionName: 'getReserveData',
429
+ args: [assetAddress],
430
+ })) as {
431
+ aTokenAddress: Address
432
+ }
433
+
434
+ const aTokenAddress = reserveData.aTokenAddress
435
+
436
+ const balance = await publicClient.readContract({
437
+ address: aTokenAddress,
438
+ abi: erc20Abi,
439
+ functionName: 'balanceOf',
440
+ args: [params.walletAddress],
441
+ })
442
+
443
+ const balanceFormatted = formatUnits(
444
+ balance,
445
+ market.asset.metadata.decimals,
446
+ )
447
+
448
+ return {
449
+ balance,
450
+ balanceFormatted,
451
+ shares: balance, // In Aave, aTokens are 1:1 with underlying
452
+ sharesFormatted: balanceFormatted,
453
+ marketId: params.marketId,
454
+ }
455
+ } catch (error) {
456
+ throw new Error(
457
+ `Failed to get market balance for ${params.walletAddress} in market ${params.marketId.address}: ${
458
+ error instanceof Error ? error.message : 'Unknown error'
459
+ }`,
460
+ )
461
+ }
462
+ }
463
+ }
@@ -0,0 +1,95 @@
1
+ import type { Address } from 'viem'
2
+ import { base, baseSepolia, optimism, optimismSepolia } from 'viem/chains'
3
+
4
+ /**
5
+ * Aave V3 Pool addresses for Optimism Superchain networks
6
+ * @description Hardcoded Pool contract addresses for each supported chain
7
+ */
8
+
9
+ /**
10
+ * Mainnet Pool addresses
11
+ */
12
+ export const POOL_ADDRESSES_MAINNET: Record<number, Address> = {
13
+ [optimism.id]: '0x794a61358D6845594F94dc1DB02A252b5b4814aD',
14
+ [base.id]: '0xA238Dd80C259a72e81d7e4664a9801593F98d1c5',
15
+ } as const
16
+
17
+ /**
18
+ * Testnet Pool addresses
19
+ */
20
+ export const POOL_ADDRESSES_TESTNET: Record<number, Address> = {
21
+ [optimismSepolia.id]: '0xb50201558b00496a145fe76f7424749556e326d8',
22
+ [baseSepolia.id]: '0x8bAB6d1b75f19e9eD9fCe8b9BD338844fF79aE27',
23
+ } as const
24
+
25
+ /**
26
+ * All Pool addresses (mainnet + testnet)
27
+ */
28
+ export const POOL_ADDRESSES: Record<number, Address> = {
29
+ ...POOL_ADDRESSES_MAINNET,
30
+ ...POOL_ADDRESSES_TESTNET,
31
+ } as const
32
+
33
+ /**
34
+ * Get Pool address for a given chain ID
35
+ * @param chainId - Chain ID
36
+ * @returns Pool address if supported, undefined otherwise
37
+ */
38
+ export function getPoolAddress(chainId: number): Address | undefined {
39
+ return POOL_ADDRESSES[chainId]
40
+ }
41
+
42
+ /**
43
+ * Check if a chain ID has Aave V3 deployed
44
+ * @param chainId - Chain ID to check
45
+ * @returns true if Aave V3 is deployed on this chain
46
+ */
47
+ export function isAaveChainSupported(chainId: number): boolean {
48
+ return chainId in POOL_ADDRESSES
49
+ }
50
+
51
+ /**
52
+ * Get all supported chain IDs
53
+ * @returns Array of chain IDs with Aave V3 deployed
54
+ */
55
+ export function getSupportedChainIds(): number[] {
56
+ return Object.keys(POOL_ADDRESSES).map(Number)
57
+ }
58
+
59
+ /**
60
+ * Aave V3 WETHGateway addresses for Optimism Superchain networks
61
+ * @description Gateway contracts that handle native ETH wrapping and depositing
62
+ */
63
+
64
+ /**
65
+ * Mainnet WETHGateway addresses
66
+ */
67
+ export const WETH_GATEWAY_ADDRESSES_MAINNET: Record<number, Address> = {
68
+ [optimism.id]: '0x5f2508cAE9923b02316254026CD43d7902866725',
69
+ [base.id]: '0xa0d9C1E9E48Ca30c8d8C3B5D69FF5dc1f6DFfC24',
70
+ } as const
71
+
72
+ /**
73
+ * Testnet WETHGateway addresses
74
+ */
75
+ export const WETH_GATEWAY_ADDRESSES_TESTNET: Record<number, Address> = {
76
+ [optimismSepolia.id]: '0x589750BA8aF186cE5B55391B0b7148cAD43a1619',
77
+ [baseSepolia.id]: '0x0568130e794429D2eEBC4dafE18f25Ff1a1ed8b6',
78
+ } as const
79
+
80
+ /**
81
+ * All WETHGateway addresses (mainnet + testnet)
82
+ */
83
+ export const WETH_GATEWAY_ADDRESSES: Record<number, Address> = {
84
+ ...WETH_GATEWAY_ADDRESSES_MAINNET,
85
+ ...WETH_GATEWAY_ADDRESSES_TESTNET,
86
+ } as const
87
+
88
+ /**
89
+ * Get WETHGateway address for a given chain ID
90
+ * @param chainId - Chain ID
91
+ * @returns WETHGateway address if supported, undefined otherwise
92
+ */
93
+ export function getWETHGatewayAddress(chainId: number): Address | undefined {
94
+ return WETH_GATEWAY_ADDRESSES[chainId]
95
+ }