Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release (pre Mises integration) to prod #169

Merged
merged 3 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"author": "Inokentii Mazhara <[email protected]>",
"license": "MIT",
"dependencies": {
"@covalenthq/client-sdk": "^1.0.2",
"@ethersproject/address": "^5.7.0",
"@ethersproject/hash": "^5.7.0",
"@ethersproject/strings": "^5.7.0",
Expand All @@ -16,6 +17,7 @@
"@taquito/tzip12": "14.0.0",
"@taquito/tzip16": "14.0.0",
"@taquito/utils": "14.0.0",
"async-retry": "^1.3.3",
"axios": "^0.27.2",
"bignumber.js": "^9.1.0",
"body-parser": "^1.20.2",
Expand Down Expand Up @@ -49,6 +51,7 @@
"db-migration": "cd migrations/notifications && npx ts-node index.ts"
},
"devDependencies": {
"@types/async-retry": "^1.4.8",
"@types/body-parser": "^1.19.2",
"@types/express": "^4.17.17",
"@types/express-jwt": "^7.4.2",
Expand Down
50 changes: 47 additions & 3 deletions src/advertising/external-ads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export const stylePropsNames = [
'aspect-ratio',
'background',
'border',
'border-top',
'border-bottom',
'border-left',
'border-right',
'border-color',
'border-radius',
'bottom',
'box-shadow',
Expand Down Expand Up @@ -49,6 +54,7 @@ export const stylePropsNames = [
'min-inline-size',
'min-width',
'opacity',
'order',
'overflow',
'overflow-anchor',
'overflow-wrap',
Expand Down Expand Up @@ -99,6 +105,7 @@ export interface AdPlacesRule extends ExtVersionConstraints {
};
stylesOverrides?: AdStylesOverrides[];
shouldHideOriginal?: boolean;
isNative?: boolean;
}

export interface PermanentAdPlacesRule extends ExtVersionConstraints {
Expand All @@ -117,12 +124,19 @@ export interface PermanentAdPlacesRule extends ExtVersionConstraints {
insertBeforeSelector?: string;
insertAfterSelector?: string;
insertionsCount?: number;
shouldUseDivWrapper: boolean;
shouldUseDivWrapper?: boolean;
wrapperType?: string;
colsBefore?: number;
colspan?: number;
colsAfter?: number;
elementStyle?: Record<StylePropName, string>;
divWrapperStyle?: Record<StylePropName, string>;
wrapperStyle?: Record<StylePropName, string>;
elementToMeasureSelector?: string;
elementsToMeasureSelectors?: Record<'width' | 'height', string>;
stylesOverrides?: AdStylesOverrides[];
shouldHideOriginal?: boolean;
displayWidth?: string;
}

export interface AdProvidersByDomainRule extends ExtVersionConstraints {
Expand All @@ -132,7 +146,9 @@ export interface AdProvidersByDomainRule extends ExtVersionConstraints {

export interface AdProviderSelectorsRule extends ExtVersionConstraints {
selectors: string[];
negativeSelectors?: string[];
parentDepth?: number;
enableForMises?: boolean;
}

export interface AdProviderForAllSitesRule extends ExtVersionConstraints {
Expand All @@ -143,13 +159,22 @@ export interface ReplaceAdsUrlsBlacklistEntry extends ExtVersionConstraints {
regexes: string[];
}

export interface ElementsToHideOrRemoveEntry extends ExtVersionConstraints {
cssString: string;
parentDepth: number;
isMultiple: boolean;
urlRegexes: string[];
shouldHide: boolean;
}

const AD_PLACES_RULES_KEY = 'ad_places_rules';
const AD_PROVIDERS_BY_SITES_KEY = 'ad_providers_by_sites';
const AD_PROVIDERS_ALL_SITES_KEY = 'ad_providers_all_sites';
const AD_PROVIDERS_LIST_KEY = 'ad_providers_list';
const PERMANENT_AD_PLACES_RULES_KEY = 'permanent_ad_places_rules';
const PERMANENT_NATIVE_AD_PLACES_RULES_KEY = 'permanent_native_ad_places_rules';
const REPLACE_ADS_URLS_BLACKLIST_KEY = 'replace_ads_urls_blacklist';
const ELEMENTS_TO_HIDE_OR_REMOVE_KEY = 'elements_to_hide_or_remove';

export const adPlacesRulesMethods = objectStorageMethodsFactory<AdPlacesRule[]>(AD_PLACES_RULES_KEY, []);

Expand All @@ -175,6 +200,11 @@ export const replaceAdsUrlsBlacklistMethods = objectStorageMethodsFactory<Replac
[]
);

export const elementsToHideOrRemoveMethods = objectStorageMethodsFactory<ElementsToHideOrRemoveEntry[]>(
ELEMENTS_TO_HIDE_OR_REMOVE_KEY,
[]
);

export const getAdProvidersForAllSites = async () => redisClient.smembers(AD_PROVIDERS_ALL_SITES_KEY);

export const addAdProvidersForAllSites = async (providers: string[]) =>
Expand All @@ -185,5 +215,19 @@ export const removeAdProvidersForAllSites = async (providers: string[]) =>

const FALLBACK_VERSION = '0.0.0';

export const filterByVersion = <T extends ExtVersionConstraints>(rules: T[], version?: string) =>
rules.filter(({ extVersion }) => versionSatisfiesRange(version ?? FALLBACK_VERSION, extVersion));
export function filterRules<T extends ExtVersionConstraints>(rules: T[], version: string | undefined): T[];
export function filterRules<T extends ExtVersionConstraints & { enableForMises?: boolean }>(
rules: T[],
version: string | undefined,
isMisesBrowser: boolean
): T[];
export function filterRules<T extends ExtVersionConstraints & { enableForMises?: boolean }>(
rules: T[],
version: string | undefined,
isMisesBrowser = false
) {
return rules.filter(
({ extVersion, enableForMises = true }) =>
versionSatisfiesRange(version ?? FALLBACK_VERSION, extVersion) && (!isMisesBrowser || enableForMises)
);
}
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const EnvVars = {
THREE_ROUTE_API_AUTH_TOKEN: getEnv('THREE_ROUTE_API_AUTH_TOKEN'),
REDIS_URL: getEnv('REDIS_URL'),
ADMIN_USERNAME: getEnv('ADMIN_USERNAME'),
ADMIN_PASSWORD: getEnv('ADMIN_PASSWORD')
ADMIN_PASSWORD: getEnv('ADMIN_PASSWORD'),
COVALENT_API_KEY: getEnv('COVALENT_API_KEY')
};

for (const name in EnvVars) {
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { getParsedContent } from './notifications/utils/get-parsed-content.util';
import { getPlatforms } from './notifications/utils/get-platforms.util';
import { redisClient } from './redis';
import { evmRouter } from './routers/evm';
import { adRulesRouter } from './routers/slise-ad-rules';
import { getABData } from './utils/ab-test';
import { cancelAliceBobOrder } from './utils/alice-bob/cancel-alice-bob-order';
Expand Down Expand Up @@ -155,7 +156,7 @@
await redisClient.lpush('notifications', JSON.stringify(newNotification));

res.status(200).send({ message: 'Notification added successfully', notification: newNotification });
} catch (error: any) {

Check warning on line 159 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
res.status(500).send({ error: error.message });
}
});
Expand Down Expand Up @@ -334,12 +335,14 @@

app.use('/api/slise-ad-rules', adRulesRouter);

app.use('/api/evm', evmRouter);

app.post('/api/magic-square-quest/start', async (req, res) => {
try {
await startMagicSquareQuest(req.body);

res.status(200).send({ message: 'Quest successfully started' });
} catch (error: any) {

Check warning on line 345 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand All @@ -353,7 +356,7 @@
app.get('/api/magic-square-quest/participants', basicAuth, async (req, res) => {
try {
res.status(200).send(await getMagicSquareQuestParticipants());
} catch (error: any) {

Check warning on line 359 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand All @@ -367,10 +370,10 @@
app.get('/api/signing-nonce', (req, res) => {
try {
const pkh = req.query.pkh;
if (!pkh || typeof pkh !== 'string') throw new Error('PKH is not a string');

Check warning on line 373 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected value in conditional. A boolean expression is required

res.status(200).send(getSigningNonce(pkh));
} catch (error: any) {

Check warning on line 376 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand Down
68 changes: 68 additions & 0 deletions src/routers/evm/covalent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { ChainID, CovalentClient } from '@covalenthq/client-sdk';
import retry from 'async-retry';

import { EnvVars } from '../../config';
import { CodedError } from '../../utils/errors';

const client = new CovalentClient(EnvVars.COVALENT_API_KEY, { enableRetry: false, threadCount: 10 });

const RETRY_OPTIONS = { maxRetryTime: 30_000 };

export const getEvmBalances = async (walletAddress: string, chainId: string) =>
await retry(
async () =>
client.BalanceService.getTokenBalancesForWalletAddress(Number(chainId) as ChainID, walletAddress, {
nft: true,
noNftAssetMetadata: true,
quoteCurrency: 'USD',
noSpam: false
}).then(({ data, error, error_message, error_code }) => {
if (error) {
throw new CodedError(Number(error_code) || 500, error_message);
}

return data;
}),
RETRY_OPTIONS
);

export const getEvmTokensMetadata = async (walletAddress: string, chainId: string) =>
await retry(
async () =>
client.BalanceService.getTokenBalancesForWalletAddress(Number(chainId) as ChainID, walletAddress, {
nft: false,
quoteCurrency: 'USD',
noSpam: false
}).then(({ data, error, error_message, error_code }) => {
if (error) {
throw new CodedError(Number(error_code) || 500, error_message);
}

return data;
}),
RETRY_OPTIONS
);

const CHAIN_IDS_WITHOUT_CACHE_SUPPORT = [10, 11155420, 43114, 43113];

export const getEvmCollectiblesMetadata = async (walletAddress: string, chainId: string) => {
const withUncached = CHAIN_IDS_WITHOUT_CACHE_SUPPORT.includes(Number(chainId));

return await retry(
async () =>
client.NftService.getNftsForAddress(Number(chainId) as ChainID, walletAddress, {
withUncached,
noSpam: false
}).then(({ data, error, error_message, error_code }) => {
if (error) {
throw new CodedError(Number(error_code) || 500, error_message);
}

return data;
}),
RETRY_OPTIONS
);
};

export const getStringifiedResponse = (response: any) =>

Check warning on line 67 in src/routers/evm/covalent.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
JSON.stringify(response, (_, value) => (typeof value === 'bigint' ? value.toString() : value));
44 changes: 44 additions & 0 deletions src/routers/evm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Router } from 'express';

import { withCodedExceptionHandler, withEvmQueryValidation } from '../../utils/express-helpers';
import { getEvmBalances, getEvmCollectiblesMetadata, getEvmTokensMetadata, getStringifiedResponse } from './covalent';

export const evmRouter = Router();

evmRouter
.get(
'/balances',
withCodedExceptionHandler(
withEvmQueryValidation(async (_1, res, _2, evmQueryParams) => {
const { walletAddress, chainId } = evmQueryParams;

const data = await getEvmBalances(walletAddress, chainId);

res.status(200).send(getStringifiedResponse(data));
})
)
)
.get(
'/tokens-metadata',
withCodedExceptionHandler(
withEvmQueryValidation(async (_1, res, _2, evmQueryParams) => {
const { walletAddress, chainId } = evmQueryParams;

const data = await getEvmTokensMetadata(walletAddress, chainId);

res.status(200).send(getStringifiedResponse(data));
})
)
)
.get(
'/collectibles-metadata',
withCodedExceptionHandler(
withEvmQueryValidation(async (_1, res, _2, evmQueryParams) => {
const { walletAddress, chainId } = evmQueryParams;

const data = await getEvmCollectiblesMetadata(walletAddress, chainId);

res.status(200).send(getStringifiedResponse(data));
})
)
);
58 changes: 55 additions & 3 deletions src/routers/slise-ad-rules/ad-places.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Request, Router } from 'express';

import {
filterByVersion,
filterRules,
permanentNativeAdPlacesMethods,
permanentAdPlacesMethods,
adPlacesRulesMethods,
Expand All @@ -18,7 +18,7 @@ import {
} from '../../utils/schemas';

const transformAdPlaces = <T extends ExtVersionConstraints>(value: T[], req: Request) =>
filterByVersion(value, req.query.extVersion as string | undefined);
filterRules(value, req.query.extVersion as string | undefined);
const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Record<string, T[]>, req: Request) =>
transformValues(rules, value => transformAdPlaces(value, req));

Expand Down Expand Up @@ -108,6 +108,10 @@ const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Rec
* type: boolean
* description: Whether original ads banners should be hidden but not removed
* default: false
* isNative:
* type: boolean
* description: Whether the ad is native
* default: false
* example:
* urlRegexes:
* - '^https://goerli\.etherscan\.io/?$'
Expand Down Expand Up @@ -158,7 +162,6 @@ const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Rec
* - urlRegexes
* - adSelector
* - parentSelector
* - shouldUseDivWrapper
* properties:
* urlRegexes:
* type: array
Expand Down Expand Up @@ -233,6 +236,32 @@ const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Rec
* shouldUseDivWrapper:
* type: boolean
* description: Whether the ads banner should be wrapped in a div
* wrapperType:
* type: string
* enum:
* - div
* - tbody
* colsBefore:
* type: number
* integer: true
* min: 0
* description: >
* If `wrapperType` is `tbody`, this property describes how many table columns should be inserted before
* the new ads banner.
* colspan:
* type: number
* integer: true
* min: 1
* description: >
* If `wrapperType` is `tbody`, this property describes how many table columns should be spanned by the
* new ads banner.
* colsAfter:
* type: number
* integer: true
* min: 0
* description: >
* If `wrapperType` is `tbody`, this property describes how many table columns should be inserted after
* the new ads banner.
* elementStyle:
* type: object
* description: Style of the new ad banner
Expand All @@ -243,9 +272,26 @@ const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Rec
* description: Style of the div wrapper
* additionalProperties:
* type: string
* wrapperStyle:
* type: object
* description: Style of the new ad banner's wrapper
* additionalProperties:
* type: string
* elementToMeasureSelector:
* type: string
* description: A selector of the element which should be measured to define banner size
* elementsToMeasureSelectors:
* type: object
* required:
* - width
* - height
* properties:
* width:
* type: string
* description: A selector of the element which should be measured to define banner width
* height:
* type: string
* description: A selector of the element which should be measured to define banner height
* stylesOverrides:
* type: array
* items:
Expand All @@ -254,6 +300,12 @@ const transformAdPlacesDictionary = <T extends ExtVersionConstraints>(rules: Rec
* type: boolean
* description: Whether original ads banners should be hidden but not removed
* default: false
* displayWidth:
* type: string
* description: >
* A range of display widths in a semver-like format where the rule is applicable. Numbers can be only
* integers. If not specified, the rule is applicable for all display widths.
* example: '>=1024 <1280'
* example:
* urlRegexes:
* - '^https://etherscan\.io/tx/'
Expand Down
Loading
Loading