Skip to content

Commit d290156

Browse files
Improvements to the portfolio page and deploy (#3076)
* Moved all shared lambda types into a single location so it's easier later to refactor it later to some better structure Added improved error handling to the portfolio page * Added Check required secrets to the aws staging action Added new env variables for blog api --------- Co-authored-by: Marcin Ciarka <marcin@oazoapps.com>
1 parent d7f4b5a commit d290156

32 files changed

+126
-94
lines changed

.github/workflows/aws-staging.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ jobs:
2525
with:
2626
node-version: 18.12
2727

28+
- name: Check required secrets
29+
run: |
30+
required_secrets=("NOTIFICATIONS_HOST_STAGING" "NOTIFICATIONS_HOST_STAGING_GOERLI" "AJNA_SUBGRAPH_URL_STAGING" "AJNA_SUBGRAPH_URL_GOERLI" "AJNA_SUBGRAPH_V2_URL_STAGING" "AJNA_SUBGRAPH_V2_URL_GOERLI" "MIXPANEL_KEY_STAGING" "ADROLL_ADV_ID_STAGING" "ADROLL_PIX_ID_STAGING" "MAINNET_CACHE_URL_STAGING" "MAILCHIMP_ENDPOINT" "MAILCHIMP_API_KEY" "INFURA_PROJECT_ID_STAGING" "ETHERSCAN_API_KEY" "BLOCKNATIVE_API_KEY_STAGING" "SENTRY_AUTH_TOKEN" "PRODUCT_HUB_KEY" "ONE_INCH_API_KEY_STAGING" "ONE_INCH_API_URL_STAGING" "REFERRAL_SUBGRAPH_URL_STAGING" "AWS_API_GATEWAY_URL" "BLOG_POSTS_API_URL" "BLOG_POSTS_API_KEY")
31+
for secret in "${required_secrets[@]}"; do
32+
secret_value=$(printenv $secret)
33+
if [[ -z "$secret_value" ]]; then
34+
echo "::error ::Secret $secret is not set. Failing the workflow."
35+
exit 1
36+
fi
37+
done
38+
2839
- name: Extract commit hash
2940
id: vars
3041
shell: bash
@@ -81,6 +92,8 @@ jobs:
8192
ONE_INCH_API_URL: ${{ secrets.ONE_INCH_API_URL_STAGING }}
8293
REFERRAL_SUBGRAPH_URL: ${{ secrets.REFERRAL_SUBGRAPH_URL_STAGING }}
8394
AWS_API_GATEWAY_URL: ${{ secrets.AWS_API_GATEWAY_URL }}
95+
BLOG_POSTS_API_URL: ${{ secrets.BLOG_POSTS_API_URL }}
96+
BLOG_POSTS_API_KEY: ${{ secrets.BLOG_POSTS_API_KEY }}
8497
run: yarn build
8598

8699
- name: Configure AWS credentials

components/AutomationIcon.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
55
import { auto_buy, auto_sell, stop_loss, take_profit } from 'theme/icons'
66
import { Text } from 'theme-ui'
77

8-
import type { PortfolioPosition } from 'lambdas/src/portfolio-positions/types'
8+
import type { PortfolioPosition } from 'lambdas/src/shared/domain-types'
99

1010
const automationIconMap: Record<keyof PortfolioPosition['automations'], typeof stop_loss> = {
1111
autoBuy: auto_buy,

components/portfolio/PortfolioOverview.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React from 'react'
99
import { useTranslation } from 'react-i18next'
1010
import { Flex, Heading, Text } from 'theme-ui'
1111

12-
import type { PortfolioOverviewResponse } from 'lambdas/src/portfolio-overview/types'
12+
import type { PortfolioOverviewResponse } from 'lambdas/src/shared/domain-types'
1313

1414
export const PortfolioOverview = ({
1515
address,

components/portfolio/helpers/getPortfolioAccentColor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { PositionDetail } from 'lambdas/src/portfolio-positions/types'
1+
import type { PositionDetail } from 'lambdas/src/shared/domain-types'
22

33
export function getPortfolioAccentColor(accent: PositionDetail['accent']): string {
44
return accent === 'positive' ? 'success100' : 'error100'

components/portfolio/positions/PortfolioPositionAutomationIcons.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AutomationIcon } from 'components/AutomationIcon'
22
import React from 'react'
33

4-
import type { PortfolioPosition } from 'lambdas/src/portfolio-positions/types'
4+
import type { PortfolioPosition } from 'lambdas/src/shared/domain-types'
55

66
export const PortfolioPositionAutomationIcons = ({
77
automations = {},

components/portfolio/positions/PortfolioPositionBlock.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import React from 'react'
1111
import { useTranslation } from 'react-i18next'
1212
import { Box, Flex, Text } from 'theme-ui'
1313

14-
import type { PortfolioPosition } from 'lambdas/src/portfolio-positions/types'
14+
import type { PortfolioPosition } from 'lambdas/src/shared/domain-types'
1515

1616
export const PortfolioPositionBlock = ({ position }: { position: PortfolioPosition }) => {
1717
const { t: tPortfolio } = useTranslation('portfolio')

components/portfolio/positions/PortfolioPositionBlockDetail.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
77
import { question_o } from 'theme/icons'
88
import { Box, Flex, Text } from 'theme-ui'
99

10-
import type { DetailsType, PositionDetail } from 'lambdas/src/portfolio-positions/types'
10+
import type { DetailsType, PositionDetail } from 'lambdas/src/shared/domain-types'
1111

1212
export const PortfolioPositionBlockDetail = ({ detail }: { detail: PositionDetail }) => {
1313
const { t: tPortfolio } = useTranslation('portfolio')

components/portfolio/positions/PortfolioPositionsView.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next'
1313
import { question_o } from 'theme/icons'
1414
import { Box, Flex, Grid, Text } from 'theme-ui'
1515

16-
import type { PortfolioPositionsResponse } from 'lambdas/src/portfolio-positions/types'
16+
import type { PortfolioPositionsResponse } from 'lambdas/src/shared/domain-types'
1717

1818
type PortfolioPositionsViewFiltersType = {
1919
showEmptyPositions: boolean

components/portfolio/wallet/PortfolioWalletAssets.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useTranslation } from 'react-i18next'
1313
import { arrow_decrease, arrow_increase } from 'theme/icons'
1414
import { Box, Button, Flex, Text } from 'theme-ui'
1515

16-
import type { PortfolioAsset } from 'lambdas/src/portfolio-assets/types'
16+
import type { PortfolioAsset } from 'lambdas/src/shared/domain-types'
1717

1818
interface PortfolioWalletAssetsProps {
1919
assets?: PortfolioAsset[]

components/portfolio/wallet/PortfolioWalletSummary.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import React, { useMemo } from 'react'
77
import { useTranslation } from 'react-i18next'
88
import { Box, Text } from 'theme-ui'
99

10-
import type { PortfolioAsset } from 'lambdas/src/portfolio-assets/types'
10+
import type { PortfolioAsset } from 'lambdas/src/shared/domain-types'
1111

1212
interface PortfolioWalletSummaryProps {
1313
assets?: PortfolioAsset[]

components/portfolio/wallet/PortfolioWalletTopAssets.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { formatFiatBalance } from 'helpers/formatters/format'
55
import React from 'react'
66
import { Flex, Grid, Text } from 'theme-ui'
77

8-
import type { PortfolioAsset } from 'lambdas/src/portfolio-assets/types'
8+
import type { PortfolioAsset } from 'lambdas/src/shared/domain-types'
99

1010
interface PortfolioWalletTopAssetsProps {
1111
assets?: PortfolioAsset[]

components/portfolio/wallet/PortfolioWalletView.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import React, { useEffect, useMemo, useState } from 'react'
88
import { useTranslation } from 'react-i18next'
99
import { Box, Flex, Grid, Heading } from 'theme-ui'
1010

11-
import type { PortfolioAssetsResponse } from 'lambdas/src/portfolio-assets/types'
11+
import type { PortfolioAssetsResponse } from 'lambdas/src/shared/domain-types'
1212

1313
export const PortfolioWalletView = ({
1414
address,

helpers/clients/portfolio-client.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { useCallback, useMemo } from 'react'
22

3-
import type { PortfolioAssetsResponse } from 'lambdas/src/portfolio-assets/types'
4-
import type { PortfolioOverviewResponse } from 'lambdas/src/portfolio-overview/types'
5-
import type { PortfolioPositionsResponse } from 'lambdas/src/portfolio-positions/types'
3+
import type {
4+
PortfolioAssetsResponse,
5+
PortfolioOverviewResponse,
6+
PortfolioPositionsResponse,
7+
} from 'lambdas/src/shared/domain-types'
68

79
/**
810
* typed client for fetching portfolio data from aws gateway

lambdas/src/common/domain.ts

-21
This file was deleted.

lambdas/src/portfolio-assets/index.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
/* eslint-disable no-relative-import-paths/no-relative-import-paths */
22
import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda'
33

4-
import { getDefaultErrorMessage } from '../common/helpers'
5-
import { ResponseBadRequest, ResponseOk } from '../common/responses'
6-
import { getAddressFromRequest } from '../common/validators'
7-
import { PortfolioAssetsResponse, PortfolioAsset } from './types'
8-
import { DebankNetworkNameToOurs, DebankNetworkNames, DebankToken } from '../common/debank'
9-
import { NetworkNames } from '../common/domain'
4+
import { getDefaultErrorMessage } from '../shared/helpers'
5+
import { ResponseBadRequest, ResponseOk } from '../shared/responses'
6+
import { getAddressFromRequest } from '../shared/validators'
7+
import { DebankNetworkNameToOurs, DebankNetworkNames, DebankToken } from '../shared/debank'
8+
import { NetworkNames, PortfolioAsset, PortfolioAssetsResponse } from '../shared/domain-types'
109

1110
const {
1211
DEBANK_API_KEY: debankApiKey,

lambdas/src/portfolio-assets/types.ts

-15
This file was deleted.

lambdas/src/portfolio-overview/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* eslint-disable no-relative-import-paths/no-relative-import-paths */
22
import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda'
33

4-
import { getDefaultErrorMessage } from '../common/helpers'
5-
import { ResponseBadRequest, ResponseInternalServerError, ResponseOk } from '../common/responses'
6-
import { getAddressFromRequest } from '../common/validators'
7-
import type { PortfolioOverviewResponse } from './types'
8-
import { ProtocolAsset, WalletAsset } from '../common/debank'
4+
import { getDefaultErrorMessage } from '../shared/helpers'
5+
import { ResponseBadRequest, ResponseInternalServerError, ResponseOk } from '../shared/responses'
6+
import { getAddressFromRequest } from '../shared/validators'
7+
import { ProtocolAsset, WalletAsset } from '../shared/debank'
8+
import { PortfolioOverviewResponse } from '../shared/domain-types'
99

1010
const SUPPORTED_CHAIN_IDS = ['eth', 'op', 'arb', 'base']
1111

lambdas/src/portfolio-overview/types.ts

-9
This file was deleted.

lambdas/src/portfolio-positions/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* eslint-disable no-relative-import-paths/no-relative-import-paths */
22
import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda'
33

4-
import { getDefaultErrorMessage } from '../common/helpers'
5-
import { ResponseBadRequest, ResponseOk } from '../common/responses'
6-
import { getAddressFromRequest } from '../common/validators'
4+
import { getDefaultErrorMessage } from '../shared/helpers'
5+
import { ResponseBadRequest, ResponseOk } from '../shared/responses'
6+
import { getAddressFromRequest } from '../shared/validators'
77
import { mockPositionsResponse } from './mock'
88

99
export const handler = async (event: APIGatewayProxyEventV2): Promise<APIGatewayProxyResultV2> => {

lambdas/src/portfolio-positions/mock.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LendingProtocol, NetworkNames } from '../common/domain'
1+
import { LendingProtocol, NetworkNames } from '../shared/domain'
22
import { PortfolioPositionsResponse, ProductType, StrategyType } from './types'
33

44
export const mockPositionsResponse: {
File renamed without changes.

lambdas/src/common/debank.ts lambdas/src/shared/debank.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NetworkNames } from './domain'
1+
import { NetworkNames } from './domain-types'
22

33
export type ProtocolAsset = {
44
id: string

lambdas/src/portfolio-positions/types.ts lambdas/src/shared/domain-types.ts

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,24 @@
1-
import { LendingProtocol, NetworkNames } from '../common/domain'
1+
export enum NetworkNames {
2+
ethereumMainnet = 'ethereum',
3+
ethereumGoerli = 'ethereum_goerli',
4+
arbitrumMainnet = 'arbitrum',
5+
arbitrumGoerli = 'arbitrum_goerli',
6+
polygonMainnet = 'polygon',
7+
polygonMumbai = 'polygon_mumbai',
8+
optimismMainnet = 'optimism',
9+
optimismGoerli = 'optimism_goerli',
10+
baseMainnet = 'base',
11+
baseGoerli = 'base_goerli',
12+
}
13+
14+
export enum LendingProtocol {
15+
AaveV2 = 'aavev2',
16+
AaveV3 = 'aavev3',
17+
Ajna = 'ajna',
18+
Maker = 'maker',
19+
MorphoBlue = 'morphoblue',
20+
SparkV3 = 'sparkv3',
21+
}
222

323
export enum ProductType {
424
'Multiply' = 'Multiply',
@@ -75,3 +95,27 @@ export type PortfolioPosition = {
7595
export type PortfolioPositionsResponse = {
7696
positions: PortfolioPosition[]
7797
}
98+
99+
export type PortfolioOverviewResponse = {
100+
walletBalanceUsdValue: number
101+
suppliedUsdValue: number
102+
suppliedPercentageChange: number
103+
borrowedUsdValue: number
104+
borrowedPercentageChange: number
105+
totalUsdValue: number
106+
totalPercentageChange: number
107+
}
108+
109+
export type PortfolioAsset = {
110+
name: string
111+
network: NetworkNames
112+
symbol: string
113+
priceUSD: number
114+
price24hChange?: number
115+
balance: number
116+
balanceUSD: number
117+
}
118+
119+
export type PortfolioAssetsResponse = {
120+
assets: PortfolioAsset[]
121+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

lambdas/src/common/responses.ts lambdas/src/shared/responses.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { APIGatewayProxyResultV2 } from 'aws-lambda'
22

3-
import type { DefaultErrorResponse } from './types'
3+
import type { DefaultErrorResponse } from './helper-types'
44

55
export function createOkBody(obj: Record<string, any>): string {
66
return JSON.stringify(obj)
File renamed without changes.

pages/portfolio/[address].tsx

+32-14
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,43 @@ import { PortfolioWalletView } from 'components/portfolio/wallet/PortfolioWallet
77
import { TabBar } from 'components/TabBar'
88
import { usePortfolioClient } from 'helpers/clients/portfolio-client'
99
import { useRedirect } from 'helpers/useRedirect'
10-
import type { GetServerSidePropsContext } from 'next'
10+
import type { GetServerSidePropsContext, GetServerSidePropsResult } from 'next'
1111
import { useTranslation } from 'next-i18next'
1212
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
1313
import React, { useEffect, useState } from 'react'
1414
import { getAwsInfraHeader, getAwsInfraUrl } from 'server/helpers'
1515
import { Box } from 'theme-ui'
1616

17-
import type { PortfolioOverviewResponse } from 'lambdas/src/portfolio-overview/types'
17+
import type { PortfolioOverviewResponse } from 'lambdas/src/shared/domain-types'
1818

19-
export async function getServerSideProps(ctx: GetServerSidePropsContext) {
19+
type PortfolioViewProps = {
20+
address: string
21+
awsInfraUrl: string
22+
awsInfraHeader: Record<string, string>
23+
}
24+
25+
export async function getServerSideProps(
26+
ctx: GetServerSidePropsContext,
27+
): Promise<GetServerSidePropsResult<PortfolioViewProps>> {
2028
const address = ctx.query.address
21-
const awsInfraUrl = getAwsInfraUrl()
22-
const awsInfraHeader = getAwsInfraHeader()
29+
let awsInfraUrl
30+
let awsInfraHeader
31+
32+
try {
33+
awsInfraUrl = getAwsInfraUrl()
34+
awsInfraHeader = getAwsInfraHeader()
35+
if (address == null || Array.isArray(address)) {
36+
throw new Error('Address is required')
37+
}
38+
} catch (e) {
39+
console.error(e)
40+
return {
41+
redirect: {
42+
destination: '/not-found',
43+
permanent: false,
44+
},
45+
}
46+
}
2347

2448
return {
2549
props: {
@@ -31,18 +55,12 @@ export async function getServerSideProps(ctx: GetServerSidePropsContext) {
3155
}
3256
}
3357

34-
export default function PortfolioView({
35-
address,
36-
awsInfraUrl,
37-
awsInfraHeader,
38-
}: {
39-
address: string
40-
awsInfraUrl: string
41-
awsInfraHeader: Record<string, string>
42-
}) {
58+
export default function PortfolioView(props: PortfolioViewProps) {
4359
const { t: tPortfolio } = useTranslation('portfolio')
4460
const { replace } = useRedirect()
4561

62+
const { address, awsInfraUrl, awsInfraHeader } = props
63+
4664
const portfolioClient = usePortfolioClient(awsInfraUrl, awsInfraHeader)
4765

4866
// fetch data

tsconfig.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
"**/*.tsx",
3131
"runtimeConfig.js",
3232
"next-i18next.config.js",
33-
"middleware.ts"
33+
"middleware.ts",
34+
"lambdas/src/shared"
3435
],
35-
"exclude": ["node_modules", "types", "coverage", "infra"],
36+
"exclude": ["node_modules", "types", "coverage", "infra", "lambdas"],
3637
"ts-node": {
3738
"compilerOptions": {
3839
"module": "commonjs"

tsconfig.test.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"lib": ["dom", "dom.iterable", "esnext"],
77
"jsx": "react"
88
},
9-
"exclude": ["node_modules", "types", "coverage", "infra"]
9+
"exclude": ["node_modules", "types", "coverage", "infra", "lambdas"]
1010
}

0 commit comments

Comments
 (0)