Skip to content

Commit

Permalink
Yj-feat/query-params (#49)
Browse files Browse the repository at this point in the history
Co-authored-by: Karan Pargal <[email protected]>
  • Loading branch information
jagnani73 and karanpargal authored Apr 26, 2024
1 parent 1aaa297 commit e94651c
Show file tree
Hide file tree
Showing 27 changed files with 535 additions and 125 deletions.
4 changes: 2 additions & 2 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import cors from "cors";
import { config as dotenvConfig } from "dotenv";
import { GoldRushDecoder } from "../services";
import { txRouter } from "../microservices/tx/tx.routes";
import { TimestampParser } from "../utils/functions";
import { timestampParser } from "../utils/functions";

dotenvConfig();

Expand Down Expand Up @@ -36,7 +36,7 @@ app.use(
const now = new Date();
console.error("Server Error");
console.error(
`${now.toISOString()}: ${TimestampParser(now, "descriptive")}`
`${now.toISOString()}: ${timestampParser(now, "descriptive")}`
);
console.error(err);
if (err.errorCode) {
Expand Down
15 changes: 12 additions & 3 deletions microservices/tx/tx.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import {
import { validateQuery } from "../../middlewares";
import {
type DecodeTXRequest,
decodeTXRequestSchema,
decodeTXBodySchema,
decodeTXHeadersSchema,
type DecodeTXHeaders,
decodeTXQuerySchema,
type DecodeTXQuery,
} from "./tx.schema";
import { decodeLogsFromTx, fetchTxFromHash } from "./tx.service";
import { type Chain } from "@covalenthq/client-sdk";
Expand All @@ -25,6 +27,8 @@ const handleDecode = async (
const covalentApiKey = (req.headers as DecodeTXHeaders)[
"x-covalent-api-key"
];
const raw_logs = (req.query as DecodeTXQuery)["raw_logs"] === "true";
const min_usd = (req.query as DecodeTXQuery)["min_usd"] ?? 0;
const { chain_name, tx_hash } = req.body as DecodeTXRequest;
const tx = await fetchTxFromHash(
chain_name as Chain,
Expand All @@ -42,7 +46,11 @@ const handleDecode = async (
const events = await decodeLogsFromTx(
chain_name as Chain,
tx,
covalentApiKey
covalentApiKey,
{
raw_logs,
min_usd,
}
);
const parsedTx = JSON.parse(
JSON.stringify(tx_metadata, (_key, value) => {
Expand All @@ -62,6 +70,7 @@ const handleDecode = async (
txRouter.post(
"/decode",
validateQuery("headers", decodeTXHeadersSchema),
validateQuery("body", decodeTXRequestSchema),
validateQuery("query", decodeTXQuerySchema),
validateQuery("body", decodeTXBodySchema),
handleDecode
);
11 changes: 9 additions & 2 deletions microservices/tx/tx.schema.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Chains } from "@covalenthq/client-sdk";
import * as yup from "yup";

export const decodeTXRequestSchema = yup.object({
export const decodeTXBodySchema = yup.object({
chain_name: yup
.mixed()
.oneOf(Object.values(Chains), "chain_name is incorrect")
.required("chain_name is required"),
tx_hash: yup.string().trim().required("tx_hash is required"),
});

export type DecodeTXRequest = yup.InferType<typeof decodeTXRequestSchema>;
export type DecodeTXRequest = yup.InferType<typeof decodeTXBodySchema>;

export const decodeTXHeadersSchema = yup.object({
"x-covalent-api-key": yup
Expand All @@ -19,3 +19,10 @@ export const decodeTXHeadersSchema = yup.object({
});

export type DecodeTXHeaders = yup.InferType<typeof decodeTXHeadersSchema>;

export const decodeTXQuerySchema = yup.object({
raw_logs: yup.string().oneOf(["false", "true"]),
min_usd: yup.number().min(0),
});

export type DecodeTXQuery = yup.InferType<typeof decodeTXQuerySchema>;
11 changes: 9 additions & 2 deletions microservices/tx/tx.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type Chain,
type Transaction,
} from "@covalenthq/client-sdk";
import { type QueryOptions } from "../../services/decoder/decoder.types";

export const fetchTxFromHash = async (
chain_name: Chain,
Expand Down Expand Up @@ -38,8 +39,14 @@ export const fetchTxFromHash = async (
export const decodeLogsFromTx = async (
chain_name: Chain,
tx: Transaction,
covalentApiKey: string
covalentApiKey: string,
options: QueryOptions
) => {
const events = await GoldRushDecoder.decode(chain_name, tx, covalentApiKey);
const events = await GoldRushDecoder.decode(
chain_name,
tx,
covalentApiKey,
options
);
return events;
};
2 changes: 1 addition & 1 deletion scripts/add-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ const chainNameSchema = yup
const eventName: string = "<EVENT NAME>";
const abiContent: string = `[]`;
const configsContent: string = `import{type Configs}from"../../decoder.types";\n\nconst configs:Configs=[{address:"${address}",is_factory:${is_factory},protocol_name:"${protocol_name}",chain_name:"${chain_name}"}];\n\nexport default configs;`;
const decodersContent: string = `import{GoldRushDecoder}from"../../decoder";import{type EventType}from"../../decoder.types";import{DECODED_ACTION,DECODED_EVENT_CATEGORY}from"../../decoder.constants";import{decodeEventLog,type Abi}from"viem";import ABI from "./abis/${protocol_name}.abi.json";\n\nGoldRushDecoder.on("${protocol_name}:${eventName}",["${chain_name}"],ABI as Abi,async(log_event,tx,chain_name,covalent_client):Promise<EventType> =>{const{raw_log_data,raw_log_topics}=log_event;\n\nconst{args:decoded}=decodeEventLog({abi:ABI,topics:raw_log_topics as[],data:raw_log_data as \`0x\${string}\`,eventName:"${eventName}"})as{eventName:"${eventName}";args:{}};\n\nreturn{action:DECODED_ACTION.SWAPPED,category:DECODED_EVENT_CATEGORY.DEX,name:"${eventName}",protocol:{logo:log_event.sender_logo_url as string,name:log_event.sender_name as string}};});`;
const decodersContent: string = `import{GoldRushDecoder}from"../../decoder";import{type EventType}from"../../decoder.types";import{DECODED_ACTION,DECODED_EVENT_CATEGORY}from"../../decoder.constants";import{decodeEventLog,type Abi}from"viem";import ABI from "./abis/${protocol_name}.abi.json";\n\nGoldRushDecoder.on("${protocol_name}:${eventName}",["${chain_name}"],ABI as Abi,async(log_event,tx,chain_name,covalent_client,options):Promise<EventType> =>{const{raw_log_data,raw_log_topics}=log_event;\n\nconst{args:decoded}=decodeEventLog({abi:ABI,topics:raw_log_topics as[],data:raw_log_data as \`0x\${string}\`,eventName:"${eventName}"})as{eventName:"${eventName}";args:{}};\n\nreturn{action:DECODED_ACTION.SWAPPED,category:DECODED_EVENT_CATEGORY.DEX,name:"${eventName}",protocol:{logo:log_event.sender_logo_url as string,name:log_event.sender_name as string},...(options.raw_logs?{raw_log:log_event}:{})};});`;
const testContent: string = `import request from"supertest";import app from"../../../../api";import{type EventType}from"../../decoder.types";\n\ndescribe("${protocol_name}",()=>{test("${chain_name}:${eventName}",async()=>{const res=await request(app).post("/api/v1/tx/decode").set({"x-covalent-api-key":process.env.TEST_COVALENT_API_KEY}).send({chain_name:"${chain_name}",tx_hash:"<ENTER TX HASH FOR TESTING>"});const{events}=res.body as{events:EventType[]};const event=events.find(({name})=>name==="${eventName}");if(!event){throw Error("Event not found")}const testAdded:boolean=false;expect(testAdded).toEqual(true)})});`;
await writeInFile(
protocolDir,
Expand Down
22 changes: 15 additions & 7 deletions services/decoder/decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
type DecoderConfig,
type Fallbacks,
type NativeDecodingFunction,
type QueryOptions,
} from "./decoder.types";
import { encodeEventTopics, type Abi } from "viem";

Expand Down Expand Up @@ -161,22 +162,23 @@ export class GoldRushDecoder {
public static decode = async (
chain_name: Chain,
tx: Transaction,
covalent_api_key: string
covalent_api_key: string,
options: QueryOptions
) => {
const covalent_client = new CovalentClient(covalent_api_key);
const events: EventType[] = [];
const events: (EventType | null)[] = [];
if (tx.value) {
const nativeEvent = this.native_decoder(tx);
const nativeEvent = this.native_decoder(tx, options);
events.push(nativeEvent);
}

const decodedEvents = await Promise.all(
(tx.log_events ?? []).map((log) => {
(tx.log_events ?? []).map((log_event) => {
const {
raw_log_topics: [topic0_hash],
sender_address,
sender_factory_address,
} = log;
} = log_event;
const lowercaseChainName = chain_name.toLowerCase() as Chain;
const lowercaseSenderAddress = sender_address?.toLowerCase();
const lowercaseSenderFactoryAddress =
Expand All @@ -200,11 +202,17 @@ export class GoldRushDecoder {
: null;

return logFunction
? logFunction(log, tx, chain_name, covalent_client)
? logFunction(
log_event,
tx,
chain_name,
covalent_client,
options
)
: null;
})
);

return events.concat(decodedEvents.filter(Boolean) as EventType[]);
return events.concat(decodedEvents).filter(Boolean) as EventType[];
};
}
16 changes: 13 additions & 3 deletions services/decoder/decoder.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,26 @@ export interface EventType {
tokens?: EventTokens;
nfts?: EventNFTs;
details?: EventDetails;
raw_log?: LogEvent;
}

export interface QueryOptions {
raw_logs?: boolean;
min_usd?: number;
}

export type DecodingFunction = (
log_event: LogEvent,
tx: Transaction,
chain_name: Chain,
covalent_client: CovalentClient
) => Promise<EventType>;
covalent_client: CovalentClient,
options: QueryOptions
) => Promise<EventType | null>;

export type NativeDecodingFunction = (tx: Transaction) => EventType;
export type NativeDecodingFunction = (
tx: Transaction,
options: QueryOptions
) => EventType | null;

export type DecoderConfig =
| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import ABI from "./abis/approval-for-all.abi.json";
GoldRushDecoder.fallback(
"ApprovalForAll",
ABI as Abi,
async (log_event, tx, chain_name, covalent_client): Promise<EventType> => {
async (
log_event,
tx,
chain_name,
covalent_client,
options
): Promise<EventType> => {
const { raw_log_data, raw_log_topics, sender_logo_url, sender_name } =
log_event;

Expand All @@ -36,6 +42,7 @@ GoldRushDecoder.fallback(
logo: sender_logo_url as string,
name: sender_name as string,
},
...(options.raw_logs ? { raw_log: log_event } : {}),
details: [
{
heading: "Owner",
Expand Down
37 changes: 25 additions & 12 deletions services/decoder/fallbacks/approval/approval.fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import {
import { decodeEventLog, type Abi } from "viem";
import ERC20ABI from "./abis/approval-erc20.abi.json";
import ERC721ABI from "./abis/approval-erc721.abi.json";
import { TimestampParser } from "../../../../utils/functions";
import { currencyToNumber, timestampParser } from "../../../../utils/functions";
import { prettifyCurrency } from "@covalenthq/client-sdk";

GoldRushDecoder.fallback(
"Approval",
ERC20ABI as Abi,
async (log_event, tx, chain_name, covalent_client): Promise<EventType> => {
async (
log_event,
tx,
chain_name,
covalent_client,
options
): Promise<EventType | null> => {
const {
block_signed_at,
raw_log_data,
Expand Down Expand Up @@ -92,6 +98,7 @@ GoldRushDecoder.fallback(
logo: sender_logo_url as string,
name: sender_name as string,
},
...(options.raw_logs ? { raw_log: log_event } : {}),
details: details,
};

Expand All @@ -107,7 +114,7 @@ GoldRushDecoder.fallback(
type: "text",
});
} else {
const date = TimestampParser(block_signed_at, "YYYY-MM-DD");
const date = timestampParser(block_signed_at, "YYYY-MM-DD");
const { data } =
await covalent_client.PricingService.getTokenPrices(
chain_name,
Expand All @@ -119,22 +126,28 @@ GoldRushDecoder.fallback(
}
);

const pretty_quote = prettifyCurrency(
data?.[0]?.items?.[0]?.price *
(Number(decoded.value) /
Math.pow(
10,
data?.[0]?.items?.[0]?.contract_metadata
?.contract_decimals ?? 18
))
);

if (currencyToNumber(pretty_quote) < options.min_usd!) {
return null;
}

parsedData.tokens = [
{
heading: "Value",
value: decoded.value.toString(),
ticker_symbol: sender_contract_ticker_symbol,
ticker_logo: sender_logo_url,
decimals: sender_contract_decimals ?? 18,
pretty_quote: prettifyCurrency(
data?.[0]?.items?.[0]?.price *
(Number(decoded.value) /
Math.pow(
10,
data?.[0]?.items?.[0]?.contract_metadata
?.contract_decimals ?? 18
))
),
pretty_quote: pretty_quote,
},
];
}
Expand Down
36 changes: 23 additions & 13 deletions services/decoder/fallbacks/transfer/transfer.fallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import {
import { decodeEventLog, type Abi } from "viem";
import ERC20ABI from "./abis/transfer-erc20.abi.json";
import ERC721ABI from "./abis/transfer-erc721.abi.json";
import { TimestampParser } from "../../../../utils/functions";
import { currencyToNumber, timestampParser } from "../../../../utils/functions";
import { prettifyCurrency } from "@covalenthq/client-sdk";

GoldRushDecoder.fallback(
"Transfer",
ERC20ABI as Abi,
async (log_event, tx, chain_name, covalent_client): Promise<EventType> => {
async (
log_event,
tx,
chain_name,
covalent_client,
options
): Promise<EventType | null> => {
const { raw_log_data, raw_log_topics } = log_event;

let decoded:
Expand Down Expand Up @@ -83,11 +89,12 @@ GoldRushDecoder.fallback(
logo: log_event.sender_logo_url as string,
name: log_event.sender_name as string,
},
...(options.raw_logs ? { raw_log: log_event } : {}),
details: details,
};

if (decoded.value) {
const date = TimestampParser(
const date = timestampParser(
log_event.block_signed_at,
"YYYY-MM-DD"
);
Expand All @@ -102,22 +109,25 @@ GoldRushDecoder.fallback(
}
);

const pretty_quote =
const pretty_quote = prettifyCurrency(
data?.[0]?.items?.[0]?.price *
(Number(decoded.value) /
Math.pow(
10,
data?.[0]?.items?.[0]?.contract_metadata
?.contract_decimals ?? 18
));
(Number(decoded.value) /
Math.pow(
10,
data?.[0]?.items?.[0]?.contract_metadata
?.contract_decimals ?? 18
)) ?? 0
);

if (currencyToNumber(pretty_quote) < options.min_usd!) {
return null;
}

parsedData.tokens = [
{
decimals: data?.[0]?.contract_decimals ?? 18,
heading: "Token Amount",
pretty_quote: pretty_quote
? prettifyCurrency(pretty_quote)
: "",
pretty_quote: pretty_quote,
ticker_logo: data?.[0]?.logo_urls?.token_logo_url,
ticker_symbol: data?.[0]?.contract_ticker_symbol,
value: decoded.value.toString(),
Expand Down
8 changes: 6 additions & 2 deletions services/decoder/native/native.decoder.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { GoldRushDecoder } from "../decoder";
import { type EventType } from "../decoder.types";

import { currencyToNumber } from "../../../utils/functions";
import { DECODED_ACTION, DECODED_EVENT_CATEGORY } from "../decoder.constants";

GoldRushDecoder.native((tx): EventType => {
GoldRushDecoder.native((tx, options): EventType | null => {
if (currencyToNumber(tx.pretty_value_quote) < options.min_usd!) {
return null;
}

return {
action: DECODED_ACTION.NATIVE_TRANSFER,
category: DECODED_EVENT_CATEGORY.DEX,
Expand Down
Loading

0 comments on commit e94651c

Please sign in to comment.