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

Api token price service #433

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
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
67 changes: 67 additions & 0 deletions test/lib/apiTokenPriceService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { gql, request } from 'graphql-request';
import { TokenPriceService } from '../../src';
import { Network } from '../testScripts/constants';

export class ApiTokenPriceService implements TokenPriceService {
private chainKey: string;

private balancerApiUrl = 'https://api-v3.balancer.fi/';

private tokenPriceQuery = gql`
query queryTokenPrices($chainKey: GqlChain!) {
tokenGetCurrentPrices(chains: [$chainKey]) {
address
price
}
}
`;

constructor(private readonly chainId: number) {
this.chainKey = Network[chainId];
}
async getNativeAssetPriceInToken(tokenAddress: string): Promise<string> {
const { tokenGetCurrentPrices: tokenPrices } = await request(
this.balancerApiUrl,
this.tokenPriceQuery,
{
chainKey: this.chainKey,
}
);
const tokenPriceUsd = (
tokenPrices as { address: string; price: number }[]
).find(
({ address }) =>
address.toLowerCase() === tokenAddress.toLowerCase()
);
if (!tokenPriceUsd) {
throw new Error('Token Price not found in the API');
}
const nativeAssetPriceUsd = (
tokenPrices as { address: string; price: number }[]
).find(
({ address }) =>
address.toLowerCase() ===
NativeAssetAddress[
this.chainKey as keyof typeof NativeAssetAddress
]
);
if (!nativeAssetPriceUsd) {
throw new Error('Native Token Price not found in the API');
}
const tokenPriceInNativeAsset =
tokenPriceUsd.price / nativeAssetPriceUsd.price;
return String(tokenPriceInNativeAsset);
}
}

enum NativeAssetAddress {
MAINNET = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
POLYGON = '0x0000000000000000000000000000000000001010',
ARBITRUM = '0x912ce59144191c1204e64559fe8253a0e49e6548',
AVALANCHE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
BASE = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
FANTOM = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
GNOSIS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
OPTIMISM = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
ZKEVM = '0xa2036f0538221a77a3937f1379699f44945018d0',
}
4 changes: 2 additions & 2 deletions test/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ export const sorConfigEth: SorConfig = {
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
connectingTokens: [
{
symbol: 'wstEth',
symbol: 'wETH',
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
},
{
symbol: 'wEth',
symbol: 'wstETH',
address: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',
},
],
Expand Down
46 changes: 46 additions & 0 deletions test/testScripts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ export const SOR_CONFIG: Record<Network, SorConfig> = {
symbol: 'wstEth',
address: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0',
},
{
symbol: 'rEth',
address: '0xae78736cd615f374d3085123a210448e74fc6393',
},
{
symbol: 'ethX',
address: '0xa35b1b31ce002fbf2058d22f30f95d405200a15b',
},
],
triPathMidPoolIds: [
'0x1e19cf2d73a72ef1332c882f20534b6519be0276000200000000000000000112', // rETH/WETH
],
wETHwstETH: {
id: '0x32296969ef14eb0c6d29669c550d4a0449130230000200000000000000000080',
Expand Down Expand Up @@ -369,6 +380,31 @@ export const ADDRESSES = {
decimals: 18,
symbol: 'swETH',
},
BAL80WETH20: {
address: '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56',
decimals: 18,
symbol: 'BAL80WETH20',
},
vETH: {
address: '0x4bc3263eb5bb2ef7ad9ab6fb68be80e43b43801f',
decimals: 18,
symbol: 'vETH',
},
vETH_vector: {
address: '0x38d64ce1bdf1a9f24e0ec469c9cade61236fb4a0',
decimals: 18,
symbol: 'vETH_vector',
},
ezETH: {
address: '0xbf5495efe5db9ce00f80364c8b423567e58d2110',
decimals: 18,
symbol: 'ezETH',
},
weETH: {
address: '0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee',
decimals: 18,
symbol: 'weETH',
},
},
[Network.POLYGON]: {
MATIC: {
Expand Down Expand Up @@ -498,11 +534,21 @@ export const ADDRESSES = {
decimals: 6,
symbol: 'USDC',
},
USDT: {
address: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9',
decimals: 6,
symbol: 'USDT',
},
STETH: {
address: 'N/A',
decimals: 18,
symbol: 'STETH',
},
sfrxETH: {
address: '0x95ab45875cffdba1e5f451b950bc2e42c0053f39',
decimals: 18,
symbol: 'sfrxETH',
},
},
[Network.GNOSIS]: {
WETH: {
Expand Down
93 changes: 47 additions & 46 deletions test/testScripts/swapExample.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Example using SOR to find the best swap for a given pair and simulate using batchSwap.
// Requires TRADER_KEY in .env.
// Run using: $ TS_NODE_PROJECT='tsconfig.testing.json' ts-node ./test/testScripts/swapExample.ts
// Run using: yarn example ./test/testScripts/swapExample.ts
// NOTE: This is for test/debug purposes, the Balancer SDK Swaps module has a more user friendly interface for interacting with SOR:
// https://github.com/balancer-labs/balancer-sdk/tree/develop/balancer-js#swaps-module
import dotenv from 'dotenv';
Expand All @@ -8,9 +8,8 @@
import { BigNumber, parseFixed } from '@ethersproject/bignumber';
import { JsonRpcProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { Contract } from '@ethersproject/contracts';

Check warning on line 11 in test/testScripts/swapExample.ts

View workflow job for this annotation

GitHub Actions / lint

'Contract' is defined but never used
import { SOR, SwapInfo, SwapTypes } from '../../src';
import { CoingeckoTokenPriceService } from '../lib/coingeckoTokenPriceService';
import { SubgraphPoolDataService } from '../lib/subgraphPoolDataService';
import {
Network,
Expand All @@ -23,7 +22,8 @@
} from './constants';
import { buildTx, printOutput } from './utils';

import vaultArtifact from '../../src/abi/Vault.json';

Check warning on line 25 in test/testScripts/swapExample.ts

View workflow job for this annotation

GitHub Actions / lint

'vaultArtifact' is defined but never used
import { ApiTokenPriceService } from '../lib/apiTokenPriceService';

// Setup SOR with data services
function setUp(networkId: Network, provider: JsonRpcProvider): SOR {
Expand All @@ -42,9 +42,10 @@
// mockPoolDataService.setPools(poolsSource);

// Use coingecko to fetch token price information. Used to calculate cost of additonal swaps/hops.
const coingeckoTokenPriceService = new CoingeckoTokenPriceService(
networkId
);
// const coingeckoTokenPriceService = new CoingeckoTokenPriceService(
// networkId
// );
const apiTokenPriceService = new ApiTokenPriceService(networkId);
// Use the mock token price service if you want to manually set the token price in native asset
// import { mockPoolDataService } from '../lib/mockPoolDataService';
// mockTokenPriceService.setTokenPrice('0.001');
Expand All @@ -53,22 +54,22 @@
provider,
SOR_CONFIG[networkId],
subgraphPoolDataService,
coingeckoTokenPriceService
apiTokenPriceService
);
}

export async function swap(): Promise<void> {
const networkId = Network.GNOSIS;
const networkId = Network.MAINNET;
const provider = new JsonRpcProvider(PROVIDER_URLS[networkId]);
// gasPrice is used by SOR as a factor to determine how many pools to swap against.
// i.e. higher cost means more costly to trade against lots of different pools.
const gasPrice = BigNumber.from('14000000000');
// This determines the max no of pools the SOR will use to swap.
const maxPools = 4;

Check warning on line 68 in test/testScripts/swapExample.ts

View workflow job for this annotation

GitHub Actions / lint

'maxPools' is assigned a value but never used
const tokenIn = ADDRESSES[networkId].WXDAI;
const tokenOut = ADDRESSES[networkId].crvUSD;
const tokenIn = ADDRESSES[networkId].BAL80WETH20;
const tokenOut = ADDRESSES[networkId].USDC;
const swapType: SwapTypes = SwapTypes.SwapExactIn;
const swapAmount = parseFixed('200', 18);
const swapAmount = parseFixed('17', tokenIn.decimals);

const sor = setUp(networkId, provider);

Expand All @@ -81,8 +82,8 @@
tokenOut.address,
swapType,
swapAmount,
{ gasPrice, maxPools },
false
undefined,
true
);

// Simulate the swap transaction
Expand All @@ -103,41 +104,41 @@
tx.limits
);

if (![tokenIn, tokenOut].includes(ADDRESSES[networkId].STETH)) {
console.log('VAULT SWAP');
const vaultContract = new Contract(
vaultAddr,
vaultArtifact,
provider
);
// Simulates a call to `batchSwap`, returning an array of Vault asset deltas.
// Each element in the array corresponds to the asset at the same index, and indicates the number of tokens(or ETH)
// the Vault would take from the sender(if positive) or send to the recipient(if negative).
const deltas = await vaultContract.queryBatchSwap(
swapType,
swapInfo.swaps,
swapInfo.tokenAddresses,
tx.funds
);
console.log(deltas.toString());
// To actually make the trade:
// vaultContract.connect(wallet);
// const tx = await vaultContract
// .connect(wallet)
// .batchSwap(
// swapType,
// swapInfo.swaps,
// swapInfo.tokenAddresses,
// tx.funds,
// tx.limits,
// tx.deadline,
// tx.overRides
// );
// if (![tokenIn, tokenOut].includes(ADDRESSES[networkId].STETH)) {
// console.log('VAULT SWAP');
// const vaultContract = new Contract(
// vaultAddr,
// vaultArtifact,
// provider
// );
// // Simulates a call to `batchSwap`, returning an array of Vault asset deltas.
// // Each element in the array corresponds to the asset at the same index, and indicates the number of tokens(or ETH)
// // the Vault would take from the sender(if positive) or send to the recipient(if negative).
// const deltas = await vaultContract.queryBatchSwap(
// swapType,
// swapInfo.swaps,
// swapInfo.tokenAddresses,
// tx.funds
// );
// console.log(deltas.toString());
// // To actually make the trade:
// // vaultContract.connect(wallet);
// // const tx = await vaultContract
// // .connect(wallet)
// // .batchSwap(
// // swapType,
// // swapInfo.swaps,
// // swapInfo.tokenAddresses,
// // tx.funds,
// // tx.limits,
// // tx.deadline,
// // tx.overRides
// // );

// console.log(`tx: ${tx}`);
} else {
console.log('RELAYER SWAP - Execute via batchRelayer.');
}
// // console.log(`tx: ${tx}`);
// } else {
// console.log('RELAYER SWAP - Execute via batchRelayer.');
// }
} else {
console.log('No Valid Swap');
await printOutput(
Expand Down
Loading