Skip to content

Commit

Permalink
Add support for optimization tab on Aave V3 strategies. (#3207)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jakubswierczek authored Dec 15, 2023
1 parent 8f81404 commit c5331ec
Show file tree
Hide file tree
Showing 141 changed files with 13,286 additions and 266 deletions.
4 changes: 4 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,7 @@ NOTIFICATIONS_HOST_GOERLI=""

RPC_GATEWAY=
GROOVE_WIDGET_ID=

# Triggers
GET_TRIGGERS_URL=""
SETUP_TRIGGER_URL=""
22 changes: 0 additions & 22 deletions .graphqlconfig

This file was deleted.

1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ coverage
.vercel
jest.config.js
setup.js
lambdas
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
4 changes: 2 additions & 2 deletions actions/aave-like/view/get-on-chain-position.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IPosition, Tokens } from '@oasisdex/dma-library'
import type { AaveLikePosition, Tokens } from '@oasisdex/dma-library'
import { views } from '@oasisdex/dma-library'
import { getAddresses } from 'actions/aave-like/get-addresses'
import type { GetOnChainPositionParams } from 'actions/aave-like/types'
Expand All @@ -12,7 +12,7 @@ export async function getOnChainPosition({
collateralToken,
debtToken,
protocol,
}: GetOnChainPositionParams): Promise<IPosition> {
}: GetOnChainPositionParams): Promise<AaveLikePosition> {
const provider = getRpcProvider(networkId)

const _collateralToken = {
Expand Down
67 changes: 25 additions & 42 deletions blockchain/abi/account-implementation.json
Original file line number Diff line number Diff line change
@@ -1,68 +1,51 @@
[
{
"inputs": [
{
"internalType": "contract AccountGuard",
"name": "_guard",
"type": "address"
}
],
"inputs": [{ "internalType": "contract AccountGuard", "name": "_guard", "type": "address" }],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
{ "indexed": false, "internalType": "address", "name": "sender", "type": "address" },
{ "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }
],
"name": "execute",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
"name": "FundsRecived",
"type": "event"
},
{
"inputs": [
{ "internalType": "address", "name": "_target", "type": "address" },
{ "internalType": "bytes", "name": "_data", "type": "bytes" }
],
"name": "execute",
"outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "guard",
"outputs": [
{
"internalType": "contract AccountGuard",
"name": "",
"type": "address"
}
],
"outputs": [{ "internalType": "contract AccountGuard", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
{ "internalType": "address", "name": "_target", "type": "address" },
{ "internalType": "bytes", "name": "_data", "type": "bytes" }
],
"name": "send",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
},
{ "stateMutability": "payable", "type": "receive" }
]
93 changes: 86 additions & 7 deletions blockchain/better-calls/dpm-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { GasMultiplier } from './utils'
import { getOverrides } from './utils/get-overrides'
import type { EstimatedGasResult } from './utils/types'

export interface DpmExecuteParameters {
export interface DpmExecuteOperationExecutorActionParameters {
networkId: NetworkIds
proxyAddress: string
signer: ethers.Signer
Expand All @@ -24,7 +24,7 @@ export async function validateParameters({
signer,
networkId,
proxyAddress,
}: Pick<DpmExecuteParameters, 'proxyAddress' | 'signer' | 'networkId'>) {
}: Pick<DpmExecuteOperationExecutorActionParameters, 'proxyAddress' | 'signer' | 'networkId'>) {
const signerChainId = await signer.getChainId()
if (signerChainId !== networkId) {
const signerNetworkConfig = networkSetById[signerChainId]
Expand All @@ -41,6 +41,14 @@ export async function validateParameters({
}

const dpm = AccountImplementation__factory.connect(proxyAddress, signer)

const dpmOwner = await dpm.owner()
const signerAddress = await signer.getAddress()
if (dpmOwner !== signerAddress) {
throw new Error(
`Signer is not the owner of the proxy. Signer: ${signerAddress}. Owner: ${dpmOwner}`,
)
}
const contracts = getNetworkContracts(networkId)
ensureContractsExist(networkId, contracts, ['operationExecutor'])
const { operationExecutor } = contracts
Expand All @@ -53,14 +61,14 @@ export async function validateParameters({
return { dpm, operationExecutor: operationExecutorContract }
}

export async function estimateGasOnDpm({
export async function estimateGasOnDpmForOperationExecutorAction({
networkId,
proxyAddress,
signer,
calls,
operationName,
value,
}: DpmExecuteParameters): Promise<EstimatedGasResult | undefined> {
}: DpmExecuteOperationExecutorActionParameters): Promise<EstimatedGasResult | undefined> {
const { dpm, operationExecutor } = await validateParameters({ signer, networkId, proxyAddress })

const encodedCallDAta = operationExecutor.interface.encodeFunctionData('executeOp', [
Expand Down Expand Up @@ -92,14 +100,14 @@ export async function estimateGasOnDpm({
}
}

export async function createExecuteTransaction({
export async function createExecuteOperationExecutorTransaction({
networkId,
proxyAddress,
signer,
calls,
operationName,
value,
}: DpmExecuteParameters): Promise<ethers.ContractTransaction> {
}: DpmExecuteOperationExecutorActionParameters): Promise<ethers.ContractTransaction> {
const { dpm, operationExecutor } = await validateParameters({ signer, networkId, proxyAddress })

const encodedCallDAta = operationExecutor.interface.encodeFunctionData('executeOp', [
Expand All @@ -120,7 +128,7 @@ export async function createExecuteTransaction({
gasLimit: ethers.BigNumber.from(dangerTransactionEnabled.gasLimit),
})
}
const gasLimit = await estimateGasOnDpm({
const gasLimit = await estimateGasOnDpmForOperationExecutorAction({
networkId,
proxyAddress,
signer,
Expand All @@ -134,3 +142,74 @@ export async function createExecuteTransaction({
gasLimit: gasLimit?.estimatedGas ?? undefined,
})
}

export interface DpmOperationParams {
networkId: NetworkIds
proxyAddress: string
signer: ethers.Signer
value?: BigNumber
data: string
to: string
}

export async function estimateGas({
signer,
networkId,
proxyAddress,
data,
value,
to,
}: DpmOperationParams) {
const { dpm } = await validateParameters({ signer, networkId, proxyAddress })

try {
const result = await dpm.estimateGas.execute(to, data, {
...(await getOverrides(signer)),
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
})

return new BigNumber(result.toString()).multipliedBy(GasMultiplier).toFixed(0)
} catch (e) {
const message = `Error estimating gas. Action: ${data} on proxy: ${proxyAddress}. Network: ${networkId}`
console.error(message, e)
throw new Error(message, {
cause: e,
})
}
}

export async function executeTransaction({
signer,
networkId,
proxyAddress,
data,
value,
to,
}: DpmOperationParams) {
const { dpm } = await validateParameters({ signer, networkId, proxyAddress })

const dangerTransactionEnabled = isDangerTransactionEnabled()

if (dangerTransactionEnabled.enabled) {
console.warn(`Danger transaction enabled. Gas limit: ${dangerTransactionEnabled.gasLimit}`)

return await dpm.execute(to, data, {
...(await getOverrides(signer)),
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
gasLimit: ethers.BigNumber.from(dangerTransactionEnabled.gasLimit),
})
}
const gasLimit = await estimateGas({
networkId,
proxyAddress,
signer,
value,
to,
data,
})
return await dpm.execute(to, data, {
...(await getOverrides(signer)),
value: ethers.utils.parseEther(value?.toString() ?? '0').toHexString(),
gasLimit: gasLimit ?? undefined,
})
}
15 changes: 15 additions & 0 deletions blockchain/prices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ import type {
} from './prices.types'
import { getToken } from './tokensMetadata'

export async function getGasPrice(): Promise<GasPriceParams> {
const response = await fetch(`/api/gasPrice`, {
method: 'GET',
headers: {
Accept: 'application/json',
},
})
if (response.status !== 200) throw new Error(await response.text())
const { maxFeePerGas, maxPriorityFeePerGas } = await response.json()
return {
maxFeePerGas: new BigNumber(maxFeePerGas),
maxPriorityFeePerGas: new BigNumber(maxPriorityFeePerGas),
}
}

export function createGasPrice$(
onEveryBlock$: Observable<number>,
context$: Observable<Context>,
Expand Down
40 changes: 40 additions & 0 deletions blockchain/transaction-fee/get-ethereum-transaction-fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import BigNumber from 'bignumber.js'
import { getNetworkContracts } from 'blockchain/contracts'
import { getRpcProvider, NetworkIds } from 'blockchain/networks'
import { getGasPrice } from 'blockchain/prices'
import { ChainlinkPriceOracle__factory } from 'types/ethers-contracts'

export interface EthereumTransactionFee {
fee: string
feeUsd: string
ethUsdPrice: string
}

export async function getEthereumTransactionFee(
args: { estimatedGas: string } | undefined,
): Promise<EthereumTransactionFee | undefined> {
if (!args) {
return undefined
}
const { chainlinkPriceOracle } = getNetworkContracts(NetworkIds.MAINNET)
const provider = getRpcProvider(NetworkIds.MAINNET)

const gasPrice = await getGasPrice()

const fee = gasPrice.maxFeePerGas.multipliedBy(args.estimatedGas)

const priceOracleContract = ChainlinkPriceOracle__factory.connect(
chainlinkPriceOracle.ETHUSD.address,
provider,
)

const ethUsdPrice = await priceOracleContract
.latestAnswer()
.then((res) => new BigNumber(res.toString()))

return {
fee: fee.toString(),
feeUsd: fee.dividedBy(ethUsdPrice).toString(),
ethUsdPrice: ethUsdPrice.toString(),
}
}
4 changes: 2 additions & 2 deletions components/vault/VaultErrors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const KbLink = (
interface VaultErrorsProps {
errorMessages: VaultErrorMessage[]
maxGenerateAmount?: BigNumber
ilkData: { debtFloor: BigNumber; token: string }
ilkData?: { debtFloor: BigNumber; token: string }
maxWithdrawAmount?: BigNumber
autoType?: 'Auto-Buy' | 'Auto-Sell'
}
Expand All @@ -27,7 +27,7 @@ export function VaultErrors({
errorMessages,
maxGenerateAmount = zero,
maxWithdrawAmount = zero,
ilkData: { debtFloor, token },
ilkData: { debtFloor, token } = { debtFloor: zero, token: '' },
autoType,
}: VaultErrorsProps) {
const { t } = useTranslation()
Expand Down
Loading

0 comments on commit c5331ec

Please sign in to comment.