Skip to content
Open
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
40 changes: 20 additions & 20 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
node_modules
.webpack
.env
.serverless
imported-db
docker
.DS_Store
.esbuild
src/utils/imports/adapters.ts
src/adapters/peggedAssets/addNewPeggedChecklist.md
src/adapters/peggedAssets/storeCoinGeckoHistory.ts
src/adapters/peggedAssets/testAdapter.ts
src/peggedAssets/storePeggedAssets/testGetAndStore.ts
src/adapters/peggedAssets/testAllAdapters.ts
src/testGetPeggedChart.ts
src/adapters/peggedAssets/historical/
package-lock.json
src/adapters/peggedAssets/storeCoinGeckoPriceHistory.ts
api2/.api2-cache/*
.current_commit_hash
node_modules
.webpack
.serverless
imported-db
docker
.DS_Store
.esbuild
src/utils/imports/adapters.ts
src/adapters/peggedAssets/addNewPeggedChecklist.md
src/adapters/peggedAssets/storeCoinGeckoHistory.ts
src/adapters/peggedAssets/testAdapter.ts
src/peggedAssets/storePeggedAssets/testGetAndStore.ts
src/adapters/peggedAssets/testAllAdapters.ts
src/testGetPeggedChart.ts
src/adapters/peggedAssets/historical/
package-lock.json
src/adapters/peggedAssets/storeCoinGeckoPriceHistory.ts
api2/.api2-cache/*
.current_commit_hash
config.bat
39 changes: 20 additions & 19 deletions api2/ecosystem.config.js

Large diffs are not rendered by default.

262 changes: 134 additions & 128 deletions api2/routes/getChainDominance.ts
Original file line number Diff line number Diff line change
@@ -1,128 +1,134 @@
import peggedAssets from "../../src/peggedData/peggedData";
import { getTimestampAtStartOfDay } from "../../src/utils/date";
import { normalizeChain } from "../../src/utils/normalizeChain";
import { cache } from "../cache";

type tokenBalance = {
[token: string]: number | undefined;
};

export function craftChainDominanceResponse(chain: string | undefined) {
const sumDailyBalances = {} as {
[timestamp: number]: {
totalCirculating: tokenBalance;
totalCirculatingUSD: tokenBalance;
greatestMcap: {
gecko_id: string;
symbol: string;
mcap: number;
};
};
};

if (chain === undefined)
throw new Error("Must include chain as path parameter.")

const normalizedChain = normalizeChain(chain);

const lastPrices = cache.peggedPrices
const lastRates = cache.rates

const lastPeggedBalances = peggedAssets.map((pegged) => {
const lastBalance = cache.peggedAssetsData?.[pegged.id]?.lastBalance;
if (!lastBalance?.[normalizedChain]) {
return undefined;
}
if (lastBalance?.[normalizedChain].circulating === undefined) {
return undefined;
}

return {
pegged,
lastBalance,
};
})

let timestamp = 0;
// use most recent timestamp as the timestamp for every pegged balance
lastPeggedBalances.map(async (peggedBalance) => {
timestamp = Math.max(
timestamp,
getTimestampAtStartOfDay(peggedBalance?.lastBalance?.SK ?? 0)
);
})

lastPeggedBalances.map((peggedBalance) => {
if (peggedBalance === undefined) {
return;
}
let { pegged, lastBalance } = peggedBalance;
const pegType = pegged.pegType;
const peggedGeckoID = pegged.gecko_id;

let fallbackPrice = 1;
const historicalPrice = lastPrices?.[peggedGeckoID];
if (pegType === "peggedVAR") {
fallbackPrice = 0;
} else if (pegType !== "peggedUSD" && !historicalPrice) {
const ticker = pegType.slice(-3);
fallbackPrice = 1 / lastRates?.rates?.[ticker];
if (typeof fallbackPrice !== "number") {
fallbackPrice = 0;
}
}
const price = historicalPrice ? historicalPrice : fallbackPrice;

let itemBalance: any = {};
itemBalance.circulating = lastBalance[normalizedChain]?.circulating ?? {
[pegType]: 0,
};
itemBalance.mcap = itemBalance.circulating[pegType] * price;
if (itemBalance.circulating === undefined) {
return;
}

// need stricter checks here
if (itemBalance !== null) {
sumDailyBalances[timestamp] = sumDailyBalances[timestamp] || {};
sumDailyBalances[timestamp].totalCirculating =
sumDailyBalances[timestamp].totalCirculating || {};
sumDailyBalances[timestamp].totalCirculating[pegType] =
(sumDailyBalances[timestamp].totalCirculating[pegType] ?? 0) +
itemBalance.circulating[pegType];

sumDailyBalances[timestamp].totalCirculatingUSD =
sumDailyBalances[timestamp].totalCirculatingUSD || {};
sumDailyBalances[timestamp].totalCirculatingUSD[pegType] =
(sumDailyBalances[timestamp].totalCirculatingUSD[pegType] ?? 0) +
itemBalance.circulating[pegType] * price;

sumDailyBalances[timestamp].greatestMcap = sumDailyBalances[timestamp]
.greatestMcap ?? {
gecko_id: pegged.gecko_id,
symbol: pegged.symbol,
mcap: itemBalance.mcap,
};

if (sumDailyBalances[timestamp].greatestMcap.mcap < itemBalance.mcap) {
sumDailyBalances[timestamp].greatestMcap = {
gecko_id: pegged.gecko_id,
symbol: pegged.symbol,
mcap: itemBalance.mcap,
};
}
} else {
console.log("itemBalance is invalid", itemBalance, pegged, timestamp);
}
})

const response = Object.entries(sumDailyBalances).map(
([timestamp, balance]) => ({
date: timestamp,
totalCirculatingUSD: balance.totalCirculatingUSD,
greatestMcap: balance.greatestMcap,
})
);

return response;
}
import peggedAssets from "../../src/peggedData/peggedData";
import { getTimestampAtStartOfDay } from "../../src/utils/date";
import { normalizeChain } from "../../src/utils/normalizeChain";
import { cache } from "../cache";

type tokenBalance = {
[token: string]: number | undefined;
};

export function craftChainDominanceResponse(chain: string | undefined) {
const sumDailyBalances = {} as {
[timestamp: number]: {
totalCirculating: tokenBalance;
totalCirculatingUSD: tokenBalance;
greatestMcap: {
gecko_id: string;
symbol: string;
mcap: number;
};
};
};

if (chain === undefined)
throw new Error("Must include chain as path parameter.")

const normalizedChain = normalizeChain(chain);

const lastPrices = cache.peggedPrices
const lastRates = cache.rates

const lastPeggedBalances = peggedAssets.map((pegged) => {
// Same exclusions the chain totals apply in craftStablecoinChainsResponse: a
// doublecounted asset is already represented by the collateral backing it, and a dead
// asset's lastBalance is frozen at its final day with no price, so it would be valued
// at par forever. Without these the dominance figures disagree with the chain totals.
if (pegged.doublecounted) return undefined;
if (pegged.deadFrom) return undefined;
const lastBalance = cache.peggedAssetsData?.[pegged.id]?.lastBalance;
if (!lastBalance?.[normalizedChain]) {
return undefined;
}
if (lastBalance?.[normalizedChain].circulating === undefined) {
return undefined;
}

return {
pegged,
lastBalance,
};
})

let timestamp = 0;
// use most recent timestamp as the timestamp for every pegged balance
lastPeggedBalances.map(async (peggedBalance) => {
timestamp = Math.max(
timestamp,
getTimestampAtStartOfDay(peggedBalance?.lastBalance?.SK ?? 0)
);
})

lastPeggedBalances.map((peggedBalance) => {
if (peggedBalance === undefined) {
return;
}
let { pegged, lastBalance } = peggedBalance;
const pegType = pegged.pegType;
const peggedGeckoID = pegged.gecko_id;

let fallbackPrice = 1;
const historicalPrice = lastPrices?.[peggedGeckoID];
if (pegType === "peggedVAR") {
fallbackPrice = 0;
} else if (pegType !== "peggedUSD" && !historicalPrice) {
const ticker = pegType.slice(-3);
fallbackPrice = 1 / lastRates?.rates?.[ticker];
if (typeof fallbackPrice !== "number") {
fallbackPrice = 0;
}
}
const price = historicalPrice ? historicalPrice : fallbackPrice;

let itemBalance: any = {};
itemBalance.circulating = lastBalance[normalizedChain]?.circulating ?? {
[pegType]: 0,
};
itemBalance.mcap = itemBalance.circulating[pegType] * price;
if (itemBalance.circulating === undefined) {
return;
}

// need stricter checks here
if (itemBalance !== null) {
sumDailyBalances[timestamp] = sumDailyBalances[timestamp] || {};
sumDailyBalances[timestamp].totalCirculating =
sumDailyBalances[timestamp].totalCirculating || {};
sumDailyBalances[timestamp].totalCirculating[pegType] =
(sumDailyBalances[timestamp].totalCirculating[pegType] ?? 0) +
itemBalance.circulating[pegType];

sumDailyBalances[timestamp].totalCirculatingUSD =
sumDailyBalances[timestamp].totalCirculatingUSD || {};
sumDailyBalances[timestamp].totalCirculatingUSD[pegType] =
(sumDailyBalances[timestamp].totalCirculatingUSD[pegType] ?? 0) +
itemBalance.circulating[pegType] * price;

sumDailyBalances[timestamp].greatestMcap = sumDailyBalances[timestamp]
.greatestMcap ?? {
gecko_id: pegged.gecko_id,
symbol: pegged.symbol,
mcap: itemBalance.mcap,
};

if (sumDailyBalances[timestamp].greatestMcap.mcap < itemBalance.mcap) {
sumDailyBalances[timestamp].greatestMcap = {
gecko_id: pegged.gecko_id,
symbol: pegged.symbol,
mcap: itemBalance.mcap,
};
}
} else {
console.log("itemBalance is invalid", itemBalance, pegged, timestamp);
}
})

const response = Object.entries(sumDailyBalances).map(
([timestamp, balance]) => ({
date: timestamp,
totalCirculatingUSD: balance.totalCirculatingUSD,
greatestMcap: balance.greatestMcap,
})
);

return response;
}
84 changes: 42 additions & 42 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
{
"name": "stablecoin-server",
"private": true,
"version": "1.0.0",
"scripts": {
"api2-dev": "ts-node --transpile-only api2/index.ts",
"generate-lz-config": "ts-node --transpile-only src/adapters/peggedAssets/helper/scripts/generateLzConfig.ts",
"api2-prod": "bash api2/scripts/prod_start.sh",
"api2-cron-task": "npx ts-node --transpile-only api2/cron-task/index.ts",
"api2-store-rates": "npx ts-node --transpile-only api2/scripts/storeRates.ts",
"test": "cd src/adapters/peggedAssets && npx ts-node --transpile-only test",
"store-all": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node --transpile-only src/cli/storeAllPeggedAssets.ts",
"force-update": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node --transpile-only src/cli/forceUpdateAsset.ts",
"fillOld": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node src/cli/fillOld.ts",
"fillLast": "export AWS_REGION='eu-central-1' && export tableName='prod-stablecoins-table' && npx ts-node src/cli/fillLast.ts"
},
"overrides": {
"ansi-regex": "5.0.1"
},
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.918.0",
"@aws-sdk/client-s3": "^3.245.0",
"@aws-sdk/lib-dynamodb": "^3.918.0",
"@defillama/sdk": "5.0.219",
"@solana/web3.js": "^1.30.2",
"@supercharge/promise-pool": "^3.2.0",
"@types/node": "^22.5.4",
"async-retry": "^1.3.1",
"axios": "^1.7.7",
"bignumber.js": "^9.0.1",
"dotenv": "^16.4.5",
"hi-base32": "^0.5.1",
"hyper-express": "^6.16.3",
"js-sha512": "^0.9.0",
"limiter": "2.1.0",
"pact-lang-api": "^4.3.5",
"pm2": "^5.4.0",
"starknet": "^6.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
{
"name": "stablecoin-server",
"private": true,
"version": "1.0.0",
"scripts": {
"api2-dev": "ts-node --transpile-only api2/index.ts",
"generate-lz-config": "ts-node --transpile-only src/adapters/peggedAssets/helper/scripts/generateLzConfig.ts",
"api2-prod": "bash api2/scripts/prod_start.sh",
"api2-cron-task": "npx ts-node --transpile-only api2/cron-task/index.ts",
"api2-store-rates": "npx ts-node --transpile-only api2/scripts/storeRates.ts",
"test": "cd src/adapters/peggedAssets && npx ts-node --transpile-only test",
"store-all": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node --transpile-only src/cli/storeAllPeggedAssets.ts",
"force-update": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node --transpile-only src/cli/forceUpdateAsset.ts",
"fillOld": "set AWS_REGION='eu-central-1' && set tableName='prod-stablecoins-table' && npx ts-node src/cli/fillOld.ts",
"fillLast": "export AWS_REGION='eu-central-1' && export tableName='prod-stablecoins-table' && npx ts-node src/cli/fillLast.ts"
},
"overrides": {
"ansi-regex": "5.0.1"
},
"dependencies": {
"@aws-sdk/client-dynamodb": "^3.918.0",
"@aws-sdk/client-s3": "^3.245.0",
"@aws-sdk/lib-dynamodb": "^3.918.0",
"@defillama/sdk": "5.0.219",
"@solana/web3.js": "^1.30.2",
"@supercharge/promise-pool": "^3.2.0",
"@types/node": "^22.5.4",
"async-retry": "^1.3.1",
"axios": "^1.7.7",
"bignumber.js": "^9.0.1",
"dotenv": "^16.4.5",
"hi-base32": "^0.5.1",
"hyper-express": "^6.16.3",
"js-sha512": "^0.9.0",
"limiter": "2.1.0",
"pact-lang-api": "^4.3.5",
"pm2": "^5.4.0",
"starknet": "^6.0.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
Loading