Skip to content

Commit

Permalink
fix: handle unknown token (#251)
Browse files Browse the repository at this point in the history
* fix: handle unknown token

* fix: move custom error class to avoid importing unsupported syntax in tests
  • Loading branch information
bard authored Aug 23, 2023
1 parent 214c83f commit 22f8729
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 54 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ async function catchupAndWatchChain(
subscribe: (...args) => indexer.subscribe(...args),
ipfsGet: cachedIpfsGet,
priceProvider,
logger: indexerLogger,
});
},
{
Expand Down
126 changes: 76 additions & 50 deletions src/indexer/handleEvent.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Logger } from "pino";
import { JsonStorage, Event as ChainsauceEvent } from "chainsauce";
import { BigNumber, ethers } from "ethers";
import StatusesBitmap from "statuses-bitmap";
Expand All @@ -20,6 +21,7 @@ import { PriceProvider } from "../prices/provider.js";
import roundMetaPtrUpdated from "./handlers/roundMetaPtrUpdated.js";
import applicationMetaPtrUpdated from "./handlers/applicationMetaPtrUpdated.js";
import matchAmountUpdated from "./handlers/matchAmountUpdated.js";
import { UnknownTokenError } from "../prices/common.js";

enum ApplicationStatus {
PENDING = 0,
Expand Down Expand Up @@ -57,20 +59,20 @@ function updateApplicationStatus(
newStatus: Application["status"],
blockNumber: number
): Application {
const newApplication: Application = {...application}
const prevStatus = application.status;
newApplication.status = newStatus;
newApplication.statusUpdatedAtBlock = blockNumber
newApplication.statusSnapshots = [...application.statusSnapshots]

if (prevStatus !== newStatus) {
newApplication.statusSnapshots.push({
status: newStatus,
statusUpdatedAtBlock: blockNumber,
})
}
const newApplication: Application = { ...application };
const prevStatus = application.status;
newApplication.status = newStatus;
newApplication.statusUpdatedAtBlock = blockNumber;
newApplication.statusSnapshots = [...application.statusSnapshots];

if (prevStatus !== newStatus) {
newApplication.statusSnapshots.push({
status: newStatus,
statusUpdatedAtBlock: blockNumber,
});
}

return newApplication
return newApplication;
}

async function handleEvent(
Expand All @@ -85,9 +87,10 @@ async function handleEvent(
) => ethers.Contract;
ipfsGet: <T>(cid: string) => Promise<T | undefined>;
priceProvider: PriceProvider;
logger: Logger;
}
) {
const { db, subscribe, ipfsGet, priceProvider, chainId } = deps;
const { db, subscribe, ipfsGet, priceProvider, chainId, logger } = deps;

const eventName =
eventRenames[chainId]?.[originalEvent.address]?.[originalEvent.name] ??
Expand Down Expand Up @@ -322,10 +325,12 @@ async function handleEvent(
metadata: null,
createdAtBlock: event.blockNumber,
statusUpdatedAtBlock: event.blockNumber,
statusSnapshots: [{
status: "PENDING",
statusUpdatedAtBlock: event.blockNumber,
}]
statusSnapshots: [
{
status: "PENDING",
statusUpdatedAtBlock: event.blockNumber,
},
],
};

await applications.insert(application);
Expand Down Expand Up @@ -423,16 +428,24 @@ async function handleEvent(
const statusString = ApplicationStatus[status] as Application["status"];
const application = await db
.collection<Application>(`rounds/${event.address}/applications`)
.updateById(i.toString(), (application) => updateApplicationStatus(
application, statusString, event.blockNumber
));
.updateById(i.toString(), (application) =>
updateApplicationStatus(
application,
statusString,
event.blockNumber
)
);

if (application) {
await db
.collection<Application>(`rounds/${event.address}/projects`)
.updateById(application.projectId, (application) => updateApplicationStatus(
application, statusString, event.blockNumber
));
.updateById(application.projectId, (application) =>
updateApplicationStatus(
application,
statusString,
event.blockNumber
)
);
}
}
break;
Expand Down Expand Up @@ -507,26 +520,40 @@ async function handleEvent(

const token = event.args.token.toLowerCase();

const conversionUSD = await priceProvider.convertToUSD(
const conversionToUSD = await priceProvider.convertToUSD(
chainId,
token,
event.args.amount.toBigInt(),
event.blockNumber
);

const amountUSD = conversionUSD.amount;

const amountRoundToken =
round.token === token
? event.args.amount.toString()
: (
await priceProvider.convertFromUSD(
chainId,
round.token,
conversionUSD.amount,
event.blockNumber
)
).amount.toString();
const amountUSD = conversionToUSD.amount;

let amountRoundToken: string | null = null;
try {
amountRoundToken =
round.token === token
? event.args.amount.toString()
: (
await priceProvider.convertFromUSD(
chainId,
round.token,
conversionToUSD.amount,
event.blockNumber
)
).amount.toString();
} catch (err) {
if (err instanceof UnknownTokenError) {
logger.error({
msg: `Skipping event ${event.name} on chain ${chainId} due to unknown token ${round.token}`,
err,
event,
});
return;
} else {
throw err;
}
}

const vote = {
id: voteId,
Expand Down Expand Up @@ -689,12 +716,9 @@ async function handleEvent(
subscribe(
event.args.payoutContractAddress,
(
await import(
"#abis/v2/DirectPayoutStrategyImplementation.json",
{
assert: { type: "json" },
}
)
await import("#abis/v2/DirectPayoutStrategyImplementation.json", {
assert: { type: "json" },
})
).default,
event.blockNumber
);
Expand Down Expand Up @@ -722,9 +746,7 @@ async function handleEvent(
for (let i = startIndex; i < startIndex + bitmap.itemsPerRow; i++) {
const newStatus = bitmap.getStatus(i);
const application = await db
.collection<Application>(
`rounds/${round}/applications`
)
.collection<Application>(`rounds/${round}/applications`)
.findById(i.toString());

// DirectPayoutStrategy uses status 1 for signaling IN REVIEW. In order to be considered as IN REVIEW the
Expand All @@ -733,9 +755,13 @@ async function handleEvent(
const statusString = ApplicationStatus[4] as Application["status"];
await db
.collection<Application>(`rounds/${round}/applications`)
.updateById(i.toString(), (application) => updateApplicationStatus(
application, statusString, event.blockNumber
))
.updateById(i.toString(), (application) =>
updateApplicationStatus(
application,
statusString,
event.blockNumber
)
);
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/prices/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,14 @@ export function pricesFilename(chainId: number, storageDir: string): string {
export const minutes = (n: number) => n * 60 * 1000;
export const hours = (n: number) => minutes(60) * n;
export const days = (n: number) => hours(24) * n;

export class UnknownTokenError extends Error {
public constructor(
public address: string,
public chainId: number,
message?: string
) {
super(message ?? `Token ${address} not configured for chain ${chainId}`);
this.name = new.target.name;
}
}
6 changes: 2 additions & 4 deletions src/prices/provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Logger } from "pino";
import { CHAINS } from "../config.js";
import { Price, readPricesFile } from "./common.js";
import { Price, readPricesFile, UnknownTokenError } from "./common.js";

const DEFAULT_REFRESH_PRICE_INTERVAL_MS = 10000;

Expand Down Expand Up @@ -137,9 +137,7 @@ export function createPriceProvider(
(t) => t.address.toLowerCase() === tokenAddress.toLowerCase()
);
if (token === undefined) {
throw new Error(
`Token ${tokenAddress} not configured for chain ${chainId}`
);
throw new UnknownTokenError(tokenAddress, chainId);
}

const pricesForToken = (await getPrices(chainId)).filter(
Expand Down

0 comments on commit 22f8729

Please sign in to comment.