Skip to content

Commit c5331ec

Browse files
Add support for optimization tab on Aave V3 strategies. (#3207)
* Add support for optimization tab on Aave V3 strategies. This commit introduces the "isOptimizationTabEnabled" method to the Aave V3 strategy. This method checks if the optimization tab is enabled for the specific strategy type and network. This check is needed to separate the availability of the optimization tab based on the vault, as the feature is not yet supported on all vaults. Further, it adds the feature toggles for "AUTO_BUY" and "AUTO_SELL" features under the Aave protocol in the automation feature map. * λ two new functions: get-triggers, setup-trigger (#3263) * Add new lambdas and local development guide This commit introduces two new lambda functions, 'get-triggers' and 'setup-trigger', and updates the documentation to include a guide for local development. Modifications were made in 'build.mjs' and 'install.mjs' files to accommodate the new lambdas, and necessary testing configurations and package-lock.json files were added. A significant part of the change went into updating the README with new instructions for creating a new lambda and to detail instructions for local development using AWS SAM and Docker. * Adjust Autobuy view * Remove duplicates * missing labels * some changes * add loading changes * don't check the use MaxBuyPrice * steps * changes in lambdas * changes in error handling
1 parent 8f81404 commit c5331ec

File tree

141 files changed

+13286
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

141 files changed

+13286
-266
lines changed

.env.template

+4
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,7 @@ NOTIFICATIONS_HOST_GOERLI=""
6868

6969
RPC_GATEWAY=
7070
GROOVE_WIDGET_ID=
71+
72+
# Triggers
73+
GET_TRIGGERS_URL=""
74+
SETUP_TRIGGER_URL=""

.graphqlconfig

-22
This file was deleted.

.prettierignore

+1
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ coverage
1313
.vercel
1414
jest.config.js
1515
setup.js
16+
lambdas

.yarnrc.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules

actions/aave-like/view/get-on-chain-position.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IPosition, Tokens } from '@oasisdex/dma-library'
1+
import type { AaveLikePosition, Tokens } from '@oasisdex/dma-library'
22
import { views } from '@oasisdex/dma-library'
33
import { getAddresses } from 'actions/aave-like/get-addresses'
44
import type { GetOnChainPositionParams } from 'actions/aave-like/types'
@@ -12,7 +12,7 @@ export async function getOnChainPosition({
1212
collateralToken,
1313
debtToken,
1414
protocol,
15-
}: GetOnChainPositionParams): Promise<IPosition> {
15+
}: GetOnChainPositionParams): Promise<AaveLikePosition> {
1616
const provider = getRpcProvider(networkId)
1717

1818
const _collateralToken = {
+25-42
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,51 @@
11
[
22
{
3-
"inputs": [
4-
{
5-
"internalType": "contract AccountGuard",
6-
"name": "_guard",
7-
"type": "address"
8-
}
9-
],
3+
"inputs": [{ "internalType": "contract AccountGuard", "name": "_guard", "type": "address" }],
104
"stateMutability": "nonpayable",
115
"type": "constructor"
126
},
137
{
8+
"anonymous": false,
149
"inputs": [
15-
{
16-
"internalType": "address",
17-
"name": "_target",
18-
"type": "address"
19-
},
20-
{
21-
"internalType": "bytes",
22-
"name": "_data",
23-
"type": "bytes"
24-
}
10+
{ "indexed": false, "internalType": "address", "name": "sender", "type": "address" },
11+
{ "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }
2512
],
26-
"name": "execute",
27-
"outputs": [
28-
{
29-
"internalType": "bytes32",
30-
"name": "",
31-
"type": "bytes32"
32-
}
13+
"name": "FundsRecived",
14+
"type": "event"
15+
},
16+
{
17+
"inputs": [
18+
{ "internalType": "address", "name": "_target", "type": "address" },
19+
{ "internalType": "bytes", "name": "_data", "type": "bytes" }
3320
],
21+
"name": "execute",
22+
"outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
3423
"stateMutability": "payable",
3524
"type": "function"
3625
},
3726
{
3827
"inputs": [],
3928
"name": "guard",
40-
"outputs": [
41-
{
42-
"internalType": "contract AccountGuard",
43-
"name": "",
44-
"type": "address"
45-
}
46-
],
29+
"outputs": [{ "internalType": "contract AccountGuard", "name": "", "type": "address" }],
30+
"stateMutability": "view",
31+
"type": "function"
32+
},
33+
{
34+
"inputs": [],
35+
"name": "owner",
36+
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
4737
"stateMutability": "view",
4838
"type": "function"
4939
},
5040
{
5141
"inputs": [
52-
{
53-
"internalType": "address",
54-
"name": "_target",
55-
"type": "address"
56-
},
57-
{
58-
"internalType": "bytes",
59-
"name": "_data",
60-
"type": "bytes"
61-
}
42+
{ "internalType": "address", "name": "_target", "type": "address" },
43+
{ "internalType": "bytes", "name": "_data", "type": "bytes" }
6244
],
6345
"name": "send",
6446
"outputs": [],
6547
"stateMutability": "payable",
6648
"type": "function"
67-
}
49+
},
50+
{ "stateMutability": "payable", "type": "receive" }
6851
]

blockchain/better-calls/dpm-account.ts

+86-7
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { GasMultiplier } from './utils'
1111
import { getOverrides } from './utils/get-overrides'
1212
import type { EstimatedGasResult } from './utils/types'
1313

14-
export interface DpmExecuteParameters {
14+
export interface DpmExecuteOperationExecutorActionParameters {
1515
networkId: NetworkIds
1616
proxyAddress: string
1717
signer: ethers.Signer
@@ -24,7 +24,7 @@ export async function validateParameters({
2424
signer,
2525
networkId,
2626
proxyAddress,
27-
}: Pick<DpmExecuteParameters, 'proxyAddress' | 'signer' | 'networkId'>) {
27+
}: Pick<DpmExecuteOperationExecutorActionParameters, 'proxyAddress' | 'signer' | 'networkId'>) {
2828
const signerChainId = await signer.getChainId()
2929
if (signerChainId !== networkId) {
3030
const signerNetworkConfig = networkSetById[signerChainId]
@@ -41,6 +41,14 @@ export async function validateParameters({
4141
}
4242

4343
const dpm = AccountImplementation__factory.connect(proxyAddress, signer)
44+
45+
const dpmOwner = await dpm.owner()
46+
const signerAddress = await signer.getAddress()
47+
if (dpmOwner !== signerAddress) {
48+
throw new Error(
49+
`Signer is not the owner of the proxy. Signer: ${signerAddress}. Owner: ${dpmOwner}`,
50+
)
51+
}
4452
const contracts = getNetworkContracts(networkId)
4553
ensureContractsExist(networkId, contracts, ['operationExecutor'])
4654
const { operationExecutor } = contracts
@@ -53,14 +61,14 @@ export async function validateParameters({
5361
return { dpm, operationExecutor: operationExecutorContract }
5462
}
5563

56-
export async function estimateGasOnDpm({
64+
export async function estimateGasOnDpmForOperationExecutorAction({
5765
networkId,
5866
proxyAddress,
5967
signer,
6068
calls,
6169
operationName,
6270
value,
63-
}: DpmExecuteParameters): Promise<EstimatedGasResult | undefined> {
71+
}: DpmExecuteOperationExecutorActionParameters): Promise<EstimatedGasResult | undefined> {
6472
const { dpm, operationExecutor } = await validateParameters({ signer, networkId, proxyAddress })
6573

6674
const encodedCallDAta = operationExecutor.interface.encodeFunctionData('executeOp', [
@@ -92,14 +100,14 @@ export async function estimateGasOnDpm({
92100
}
93101
}
94102

95-
export async function createExecuteTransaction({
103+
export async function createExecuteOperationExecutorTransaction({
96104
networkId,
97105
proxyAddress,
98106
signer,
99107
calls,
100108
operationName,
101109
value,
102-
}: DpmExecuteParameters): Promise<ethers.ContractTransaction> {
110+
}: DpmExecuteOperationExecutorActionParameters): Promise<ethers.ContractTransaction> {
103111
const { dpm, operationExecutor } = await validateParameters({ signer, networkId, proxyAddress })
104112

105113
const encodedCallDAta = operationExecutor.interface.encodeFunctionData('executeOp', [
@@ -120,7 +128,7 @@ export async function createExecuteTransaction({
120128
gasLimit: ethers.BigNumber.from(dangerTransactionEnabled.gasLimit),
121129
})
122130
}
123-
const gasLimit = await estimateGasOnDpm({
131+
const gasLimit = await estimateGasOnDpmForOperationExecutorAction({
124132
networkId,
125133
proxyAddress,
126134
signer,
@@ -134,3 +142,74 @@ export async function createExecuteTransaction({
134142
gasLimit: gasLimit?.estimatedGas ?? undefined,
135143
})
136144
}
145+
146+
export interface DpmOperationParams {
147+
networkId: NetworkIds
148+
proxyAddress: string
149+
signer: ethers.Signer
150+
value?: BigNumber
151+
data: string
152+
to: string
153+
}
154+
155+
export async function estimateGas({
156+
signer,
157+
networkId,
158+
proxyAddress,
159+
data,
160+
value,
161+
to,
162+
}: DpmOperationParams) {
163+
const { dpm } = await validateParameters({ signer, networkId, proxyAddress })
164+
165+
try {
166+
const result = await dpm.estimateGas.execute(to, data, {
167+
...(await getOverrides(signer)),
168+
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
169+
})
170+
171+
return new BigNumber(result.toString()).multipliedBy(GasMultiplier).toFixed(0)
172+
} catch (e) {
173+
const message = `Error estimating gas. Action: ${data} on proxy: ${proxyAddress}. Network: ${networkId}`
174+
console.error(message, e)
175+
throw new Error(message, {
176+
cause: e,
177+
})
178+
}
179+
}
180+
181+
export async function executeTransaction({
182+
signer,
183+
networkId,
184+
proxyAddress,
185+
data,
186+
value,
187+
to,
188+
}: DpmOperationParams) {
189+
const { dpm } = await validateParameters({ signer, networkId, proxyAddress })
190+
191+
const dangerTransactionEnabled = isDangerTransactionEnabled()
192+
193+
if (dangerTransactionEnabled.enabled) {
194+
console.warn(`Danger transaction enabled. Gas limit: ${dangerTransactionEnabled.gasLimit}`)
195+
196+
return await dpm.execute(to, data, {
197+
...(await getOverrides(signer)),
198+
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
199+
gasLimit: ethers.BigNumber.from(dangerTransactionEnabled.gasLimit),
200+
})
201+
}
202+
const gasLimit = await estimateGas({
203+
networkId,
204+
proxyAddress,
205+
signer,
206+
value,
207+
to,
208+
data,
209+
})
210+
return await dpm.execute(to, data, {
211+
...(await getOverrides(signer)),
212+
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
213+
gasLimit: gasLimit ?? undefined,
214+
})
215+
}

blockchain/prices.ts

+15
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ import type {
1919
} from './prices.types'
2020
import { getToken } from './tokensMetadata'
2121

22+
export async function getGasPrice(): Promise<GasPriceParams> {
23+
const response = await fetch(`/api/gasPrice`, {
24+
method: 'GET',
25+
headers: {
26+
Accept: 'application/json',
27+
},
28+
})
29+
if (response.status !== 200) throw new Error(await response.text())
30+
const { maxFeePerGas, maxPriorityFeePerGas } = await response.json()
31+
return {
32+
maxFeePerGas: new BigNumber(maxFeePerGas),
33+
maxPriorityFeePerGas: new BigNumber(maxPriorityFeePerGas),
34+
}
35+
}
36+
2237
export function createGasPrice$(
2338
onEveryBlock$: Observable<number>,
2439
context$: Observable<Context>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import BigNumber from 'bignumber.js'
2+
import { getNetworkContracts } from 'blockchain/contracts'
3+
import { getRpcProvider, NetworkIds } from 'blockchain/networks'
4+
import { getGasPrice } from 'blockchain/prices'
5+
import { ChainlinkPriceOracle__factory } from 'types/ethers-contracts'
6+
7+
export interface EthereumTransactionFee {
8+
fee: string
9+
feeUsd: string
10+
ethUsdPrice: string
11+
}
12+
13+
export async function getEthereumTransactionFee(
14+
args: { estimatedGas: string } | undefined,
15+
): Promise<EthereumTransactionFee | undefined> {
16+
if (!args) {
17+
return undefined
18+
}
19+
const { chainlinkPriceOracle } = getNetworkContracts(NetworkIds.MAINNET)
20+
const provider = getRpcProvider(NetworkIds.MAINNET)
21+
22+
const gasPrice = await getGasPrice()
23+
24+
const fee = gasPrice.maxFeePerGas.multipliedBy(args.estimatedGas)
25+
26+
const priceOracleContract = ChainlinkPriceOracle__factory.connect(
27+
chainlinkPriceOracle.ETHUSD.address,
28+
provider,
29+
)
30+
31+
const ethUsdPrice = await priceOracleContract
32+
.latestAnswer()
33+
.then((res) => new BigNumber(res.toString()))
34+
35+
return {
36+
fee: fee.toString(),
37+
feeUsd: fee.dividedBy(ethUsdPrice).toString(),
38+
ethUsdPrice: ethUsdPrice.toString(),
39+
}
40+
}

components/vault/VaultErrors.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const KbLink = (
1818
interface VaultErrorsProps {
1919
errorMessages: VaultErrorMessage[]
2020
maxGenerateAmount?: BigNumber
21-
ilkData: { debtFloor: BigNumber; token: string }
21+
ilkData?: { debtFloor: BigNumber; token: string }
2222
maxWithdrawAmount?: BigNumber
2323
autoType?: 'Auto-Buy' | 'Auto-Sell'
2424
}
@@ -27,7 +27,7 @@ export function VaultErrors({
2727
errorMessages,
2828
maxGenerateAmount = zero,
2929
maxWithdrawAmount = zero,
30-
ilkData: { debtFloor, token },
30+
ilkData: { debtFloor, token } = { debtFloor: zero, token: '' },
3131
autoType,
3232
}: VaultErrorsProps) {
3333
const { t } = useTranslation()

0 commit comments

Comments
 (0)