Skip to content

Commit

Permalink
Feat/etherfi points (#742)
Browse files Browse the repository at this point in the history
* fix: create etherfi points worker

* fix: making points worker

* fix: rename to points

* fix: adding ezETH vault
  • Loading branch information
jeffywu authored Apr 8, 2024
1 parent eadfc3c commit fdcb9b3
Show file tree
Hide file tree
Showing 16 changed files with 376 additions and 1 deletion.
5 changes: 4 additions & 1 deletion apps/deployWorkers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ yarn nx publish-wrangler-manual rewards --env dev
yarn nx publish-wrangler-manual liquidation-bot --env arbitrum
yarn nx publish-wrangler-manual liquidation-bot --env mainnet
yarn nx publish-wrangler-manual vault-liquidator --env arbitrum
yarn nx publish-wrangler-manual vault-liquidator --env mainnet
yarn nx publish-wrangler-manual vault-liquidator --env mainnet

# Points
yarn nx publish-wrangler-manual points --env prod
1 change: 1 addition & 0 deletions apps/points/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
EXAMPLE_SECRET = 'SECRET_KEY'
18 changes: 18 additions & 0 deletions apps/points/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
24 changes: 24 additions & 0 deletions apps/points/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* eslint-disable */
export default {
displayName: 'points',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
useESM: true,
},
},
testEnvironment: 'miniflare',
testEnvironmentOptions: {
scriptPath: 'apps/points/dist/index.js',
modules: true,
wranglerConfigPath: 'apps/points/wrangler.toml',
wranglerConfigEnv: 'apps/points/.dev.vars',
},
transform: {
'^.+\\.[tj]s$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js'],
coverageDirectory: '../../coverage/apps/points',
testTimeout: 50000,
};
58 changes: 58 additions & 0 deletions apps/points/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "points",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/points/src",
"projectType": "application",
"targets": {
"serve": {
"executor": "nx:run-commands",
"options": {
"commands": [
{
"command": "wrangler dev --var NX_COMMIT_REF:$(git rev-parse HEAD)"
}
],
"cwd": "apps/points"
}
},
"publish-wrangler-manual": {
"executor": "nx:run-commands",
"options": {
"commands": [
{
"command": "wrangler deploy --env {args.env} --var NX_COMMIT_REF:$(git rev-parse HEAD)"
}
],
"cwd": "apps/points"
}
},
"publish-wrangler": {
"executor": "nx:run-commands",
"options": {
"commands": [
{
"command": "wrangler deploy"
}
],
"cwd": "apps/points"
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/points/**/*.ts"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/points"],
"options": {
"jestConfig": "apps/points/jest.config.ts",
"passWithNoTests": true
},
"dependsOn": ["build"]
}
},
"tags": []
}
137 changes: 137 additions & 0 deletions apps/points/src/calculate-points.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import {
BalancerBoostedPoolABI,
BalancerVault,
BalancerVaultABI,
ISingleSidedLPStrategyVaultABI,
} from '@notional-finance/contracts';
import { aggregate } from '@notional-finance/multicall';
import { Network, getProviderFromNetwork } from '@notional-finance/util';
import { BigNumber, Contract, ethers, providers } from 'ethers';
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { AllVaultAccountsQuery } from 'packages/core-entities/src/.graphclient';

const VaultConfig = {
'0x32d82a1c8618c7be7fe85b2f1c44357a871d52d1': {
poolId:
'0x05ff47afada98a98982113758878f9a8b9fdda0a000000000000000000000645',
targetToken: '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee',
network: Network.mainnet,
symbol: 'weETH',
},
'0x914255c0c289aea36e378ebb5e28293b5ed278ca': {
poolId:
'0x596192bb6e41802428ac943d2f1476c1af25cc0e000000000000000000000659',
targetToken: '0xbf5495Efe5DB9ce00f80364C8B423567e58d2110',
network: Network.mainnet,
symbol: 'ezETH',
},
};

async function loadAllVaultsQuery(
vaultAddress: string,
blockNumber: number,
network: Network
) {
const {
execute,
AllVaultAccountsDocument,
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
} = await import('../../../packages/core-entities/src/.graphclient/index');

return await execute(
AllVaultAccountsDocument,
{
vaultAddress,
blockNumber,
},
{ chainName: network }
).then((d) => d.data as AllVaultAccountsQuery);
}

export async function getVaultData(vaultAddress: string, blockNumber: number) {
const { targetToken, poolId, network, symbol } = VaultConfig[vaultAddress];

const { results: vaultInfo } = (await aggregate<unknown>(
[
{
target: new Contract(
vaultAddress,
ISingleSidedLPStrategyVaultABI,
getProviderFromNetwork(network)
),
method: 'getStrategyVaultInfo',
key: 'info',
},
],
getProviderFromNetwork(network, true),
blockNumber
)) as unknown as {
block: providers.Block;
results: {
info: Awaited<ReturnType<BalancerVault['functions']['getPoolTokens']>>;
};
};

const { results: poolData } = (await aggregate<{
totalSupply: BigNumber;
balances: Awaited<ReturnType<BalancerVault['functions']['getPoolTokens']>>;
}>(
[
{
stage: 0,
target: new Contract(vaultInfo.info['pool'], BalancerBoostedPoolABI),
method: 'getActualSupply',
key: 'totalSupply',
args: [],
},
{
target: new Contract(
'0xBA12222222228d8Ba445958a75a0704d566BF2C8',
BalancerVaultABI
),
method: 'getPoolTokens',
args: [poolId],
key: 'balances',
},
],
getProviderFromNetwork(network, true),
blockNumber
)) as unknown as {
block: providers.Block;
results: {
totalSupply: BigNumber;
balances: Awaited<
ReturnType<BalancerVault['functions']['getPoolTokens']>
>;
};
};

const allVaultAccounts = await loadAllVaultsQuery(
vaultAddress,
blockNumber,
network
);

const totalLPTokens: BigNumber = vaultInfo.info['totalLPTokens'];
const totalVaultShares: BigNumber = vaultInfo.info['totalVaultShares'];
const totalLPSupply: BigNumber = poolData.totalSupply;
const tokenIndex = poolData.balances.tokens.findIndex(
(t) => t === targetToken
);
const totalTokenBalance: BigNumber = poolData.balances.balances[tokenIndex];

return allVaultAccounts.balances.map((a) => {
const lpTokens = totalLPTokens
.mul(BigNumber.from(a.current.currentBalance))
.div(totalVaultShares);
const tokenBalance = totalTokenBalance.mul(lpTokens).div(totalLPSupply);

return {
address: a.account.id,
effective_balance: `${ethers.utils.formatUnits(
tokenBalance,
18
)} ${symbol}`,
};
});
}
18 changes: 18 additions & 0 deletions apps/points/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getVaultData } from './calculate-points';

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Env {}

export default {
async fetch(
request: Request,
_env: Env,
_ctx: ExecutionContext
): Promise<Response> {
const url = new URL(request.url);
const [_, vaultAddress, blockNumber] = url.pathname.split('/', 3);
return new Response(
JSON.stringify(await getVaultData(vaultAddress, parseInt(blockNumber)))
);
},
};
8 changes: 8 additions & 0 deletions apps/points/test/globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
declare global {
function getMiniflareBindings(): Bindings;
function getMiniflareDurableObjectStorage(
id: DurableObjectId
): Promise<DurableObjectStorage>;
}

export {};
11 changes: 11 additions & 0 deletions apps/points/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// See example here: https://blog.cloudflare.com/miniflare/
import worker from '../src/index';

const env = getMiniflareBindings();

test('should return a 200', async () => {
// Note we're using Worker APIs in our test, without importing anything extra
const request = new Request('http://localhost/');
const response = await worker.fetch(request, env);
expect(response.status).toBe(200);
});
9 changes: 9 additions & 0 deletions apps/points/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs"
},
"exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"],
"include": ["**/*.ts"]
}
17 changes: 17 additions & 0 deletions apps/points/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"lib": ["esnext"],
"types": ["node", "@cloudflare/workers-types"]
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
9 changes: 9 additions & 0 deletions apps/points/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node", "@cloudflare/workers-types", "bindings"]
},
"include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
}
10 changes: 10 additions & 0 deletions apps/points/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
main = "./src/index.ts"
compatibility_date = "2022-11-11"

workers_dev = true
node_compat = true
minify = true
logpush = true

[env.prod]
name = "points-prod"
Loading

0 comments on commit fdcb9b3

Please sign in to comment.