@aurigami/sdk 1.24.0 → 1.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/consts/constants.d.ts +3 -1
- package/dist/consts/constants.js +4 -2
- package/dist/entities/auriEnv.d.ts +2 -1
- package/dist/entities/auriEnv.js +3 -3
- package/dist/helpers/priceFetcher.js +9 -13
- package/dist/interactors/misc.js +2 -2
- package/package.json +2 -14
- package/src/SDK.ts +0 -223
- package/src/abis/index.ts +0 -38
- package/src/consts/constants.ts +0 -210
- package/src/consts/decimals.ts +0 -31
- package/src/consts/deployments.ts +0 -4
- package/src/consts/dummy.ts +0 -51
- package/src/consts/index.ts +0 -5
- package/src/consts/symbols.ts +0 -9
- package/src/entities/BlockchainEntity.ts +0 -29
- package/src/entities/auriEnv.ts +0 -180
- package/src/entities/index.ts +0 -4
- package/src/entities/token.ts +0 -21
- package/src/entities/tokenAmount.ts +0 -48
- package/src/helpers/aurigami-api.ts +0 -42
- package/src/helpers/aurora-api-helpers.ts +0 -17
- package/src/helpers/graphql-helpers.ts +0 -8
- package/src/helpers/helpers.ts +0 -212
- package/src/helpers/historicalPriceFetcher.ts +0 -200
- package/src/helpers/index.ts +0 -7
- package/src/helpers/kyber-aggregator-api.ts +0 -37
- package/src/helpers/multicall.ts +0 -251
- package/src/helpers/notification-api.ts +0 -22
- package/src/helpers/one-inch-aggregator-api.ts +0 -45
- package/src/helpers/priceFetcher.ts +0 -388
- package/src/helpers/subgraphQuery.ts +0 -17
- package/src/helpers/transfer-event-query.ts +0 -68
- package/src/index.ts +0 -14
- package/src/interactors/Airdrop.ts +0 -72
- package/src/interactors/MoneyMarket.ts +0 -486
- package/src/interactors/Multicall.ts +0 -50
- package/src/interactors/Papermill.ts +0 -185
- package/src/interactors/PlyGame.ts +0 -172
- package/src/interactors/PlyTokenLock.ts +0 -46
- package/src/interactors/Pulp.ts +0 -41
- package/src/interactors/Referral.ts +0 -214
- package/src/interactors/Staking.ts +0 -156
- package/src/interactors/index.ts +0 -9
- package/src/interactors/misc.ts +0 -433
- package/src/types/index.ts +0 -252
package/src/helpers/helpers.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { TypedEvent } from '@aurigami/contracts/typechain/common';
|
|
2
|
-
import { Provider } from '@ethersproject/abstract-provider';
|
|
3
|
-
import BigNumber from 'bignumber.js';
|
|
4
|
-
import { BigNumber as BN, utils } from 'ethers';
|
|
5
|
-
import { Result } from 'ethers/lib/utils';
|
|
6
|
-
import { GRAPHQL_URL, networkAddresses } from '../consts/constants';
|
|
7
|
-
import { decimalRecords } from '../consts/decimals';
|
|
8
|
-
import { symbolRecords } from '../consts/symbols';
|
|
9
|
-
import { Address } from '../types';
|
|
10
|
-
import { getQuery as getAuroraAPIQuery } from './aurora-api-helpers';
|
|
11
|
-
import { queryGraphQL } from './graphql-helpers';
|
|
12
|
-
|
|
13
|
-
export function assert(condition: boolean, message: string = ''): void {
|
|
14
|
-
if (!condition) {
|
|
15
|
-
message = 'Assertion failed' + (message ? ': ' + message : '');
|
|
16
|
-
throw new Error(message);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function formatObject(object: Object) {
|
|
21
|
-
return JSON.stringify(object, null, ' ');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function decimalFactor(decimal: number) {
|
|
25
|
-
return BN.from(10).pow(decimal).toString();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const isSameAddress = (address1: Address, address2: Address): boolean => {
|
|
29
|
-
return address1.toLowerCase() == address2.toLowerCase();
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const getCurrentTimestamp = (): number => {
|
|
33
|
-
return Math.trunc(Date.now() / 1000);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export async function sleep(duration: number): Promise<void> {
|
|
37
|
-
return new Promise((resolve) => {
|
|
38
|
-
setTimeout(resolve, duration);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function validateAndParseAddress(address: Address): Address {
|
|
43
|
-
try {
|
|
44
|
-
return utils.getAddress(address);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
throw new Error('Invalid address: ' + address);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function getDecimal(address: Address): number {
|
|
51
|
-
let addressLowercase = address.toLowerCase();
|
|
52
|
-
assert(decimalRecords[addressLowercase] != undefined, 'Decimal not found for ' + address);
|
|
53
|
-
return decimalRecords[addressLowercase];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function getSymbol(address: Address): string {
|
|
57
|
-
let addressLowercase = address.toLowerCase();
|
|
58
|
-
assert(symbolRecords[addressLowercase] != undefined, 'Symbol not found for ' + address);
|
|
59
|
-
return symbolRecords[addressLowercase];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function getUnderlying(address: Address): Address {
|
|
63
|
-
let addressLowercase = address.toLowerCase();
|
|
64
|
-
let matching = networkAddresses.auTokens.filter((e) => e.address == addressLowercase);
|
|
65
|
-
if (matching.length == 0) {
|
|
66
|
-
throw new Error('Underlying not found for ' + address);
|
|
67
|
-
}
|
|
68
|
-
return matching[0].underlying;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function calcLMRewardApr(
|
|
72
|
-
rewardsValue: BigNumber,
|
|
73
|
-
totalStakeValue: BigNumber,
|
|
74
|
-
frequencyPerYear: number
|
|
75
|
-
): BigNumber {
|
|
76
|
-
if (rewardsValue.isZero()) {
|
|
77
|
-
return new BigNumber(0);
|
|
78
|
-
}
|
|
79
|
-
if (totalStakeValue.lte(0)) {
|
|
80
|
-
// avoid division by zero when there is no stake
|
|
81
|
-
return rewardsValue;
|
|
82
|
-
}
|
|
83
|
-
return rewardsValue.multipliedBy(frequencyPerYear).dividedBy(totalStakeValue);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function calcNetApy(
|
|
87
|
-
suppliedValue: BigNumber,
|
|
88
|
-
supplyApy: BigNumber,
|
|
89
|
-
borrowedValue: BigNumber,
|
|
90
|
-
borrowApy: BigNumber
|
|
91
|
-
) {
|
|
92
|
-
return suppliedValue.multipliedBy(supplyApy).minus(borrowedValue.multipliedBy(borrowApy));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export async function getBlockTimestamp(provider: Provider, blockNumber: number): Promise<number> {
|
|
96
|
-
const block = await provider.getBlock(blockNumber);
|
|
97
|
-
return block.timestamp;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export async function getBlocksTimestampViaRPC(
|
|
101
|
-
provider: Provider,
|
|
102
|
-
blocksNumber: number[]
|
|
103
|
-
): Promise<number[]> {
|
|
104
|
-
// Promise all 200 blocks at a time, using too many blocks at once will cause the RPC call timeout.
|
|
105
|
-
const CHUNK_SIZE = 200;
|
|
106
|
-
let results: number[] = [];
|
|
107
|
-
for (let i = 0; i < blocksNumber.length; i += CHUNK_SIZE) {
|
|
108
|
-
let slice = blocksNumber.slice(i, i + CHUNK_SIZE);
|
|
109
|
-
let promises = slice.map(async (blockNumber) => getBlockTimestamp(provider, blockNumber));
|
|
110
|
-
results = results.concat(await Promise.all(promises));
|
|
111
|
-
}
|
|
112
|
-
return results;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Get timestamp of multiple blocks.
|
|
117
|
-
* @note the getBlockTimestamp function is too slow because of the RPC call, even with Promise.all.
|
|
118
|
-
* So I use the GraphQL endpoint of Aurora instead. You can check it here: https://explorer.mainnet.aurora.dev/graphiql
|
|
119
|
-
*/
|
|
120
|
-
export async function getBlocksTimestamp(
|
|
121
|
-
provider: Provider,
|
|
122
|
-
blockNumbers: number[]
|
|
123
|
-
): Promise<number[]> {
|
|
124
|
-
if (blockNumbers.length == 0) return [];
|
|
125
|
-
const CHUNK_SIZE = 100; // graphql query limit
|
|
126
|
-
|
|
127
|
-
let promises = [];
|
|
128
|
-
let lines: string[] = blockNumbers.map((x) => `b${x}: block(number: ${x}) { timestamp }`);
|
|
129
|
-
|
|
130
|
-
for (let i = 0; i < lines.length; i += CHUNK_SIZE) {
|
|
131
|
-
let query = `{ ${lines.slice(i, i + CHUNK_SIZE).join('\n')} }`;
|
|
132
|
-
promises.push(queryGraphQL(query, GRAPHQL_URL));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// merge all the json objects
|
|
136
|
-
let results = (await Promise.all(promises)).reduce((acc, cur) => {
|
|
137
|
-
return { ...acc, ...cur };
|
|
138
|
-
}, {});
|
|
139
|
-
|
|
140
|
-
let missingBlocks = blockNumbers.filter((blockNumber) => !results[`b${blockNumber}`]);
|
|
141
|
-
if (missingBlocks.length > 0) {
|
|
142
|
-
devLog(`These blocks are missing from Aurora GraphQL endpoint: ${missingBlocks.join(', ')}`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
let missingBlocksTimestamps = await getBlocksTimestampViaRPC(provider, missingBlocks);
|
|
146
|
-
|
|
147
|
-
missingBlocksTimestamps.forEach((timestamp, index) => {
|
|
148
|
-
results[`b${missingBlocks[index]}`] = { timestamp: new Date(timestamp * 1000).toISOString() };
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return blockNumbers.map((blockNumber) =>
|
|
152
|
-
Math.trunc(new Date(results[`b${blockNumber}`]!.timestamp).getTime() / 1000)
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Get the block number of the last block that has a timestamp before the given timestamp
|
|
158
|
-
* @param timestamp input timestamp
|
|
159
|
-
* @returns return the last block that its timestamp <= the give timestamp
|
|
160
|
-
* @note Check this API for more information: https://aurorascan.dev/apis#blocks
|
|
161
|
-
*
|
|
162
|
-
* This function is much faster than using binary search.
|
|
163
|
-
*/
|
|
164
|
-
export async function getBlockBeforeTimestamp(provider: Provider, timestamp: number) {
|
|
165
|
-
let result = await getAuroraAPIQuery('block', 'getblocknobytime', {
|
|
166
|
-
timestamp: timestamp,
|
|
167
|
-
closest: 'before',
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// In case the API return `Block timestamp too far in the future`
|
|
171
|
-
// use the last block number
|
|
172
|
-
return parseInt(result.blockNumber) || (await provider.getBlockNumber());
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function devLog(message?: any, ...optionalParams: any[]): void {
|
|
176
|
-
if ('production' !== process.env.NODE_ENV) {
|
|
177
|
-
console.log('[DEV LOG]', message, ...optionalParams);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Sorts (in place) an array of Events by blocknumber.
|
|
183
|
-
* This method mutates the array and returns a reference to the same array.
|
|
184
|
-
**/
|
|
185
|
-
export function sortEvents<T extends Result>(events: TypedEvent<T>[]): TypedEvent<T>[] {
|
|
186
|
-
return events.sort((a, b) => {
|
|
187
|
-
if (a.blockNumber == b.blockNumber) {
|
|
188
|
-
return a.logIndex - b.logIndex;
|
|
189
|
-
}
|
|
190
|
-
return a.blockNumber - b.blockNumber;
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// export function Cache(cacheTimeout: number) {
|
|
195
|
-
// return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
|
196
|
-
// const originalMethod = descriptor.value;
|
|
197
|
-
// let cache = new Map<string, any>();
|
|
198
|
-
// descriptor.value = function (...args: any[]) {
|
|
199
|
-
// let key = JSON.stringify(args);
|
|
200
|
-
// if (cache.has(key)) {
|
|
201
|
-
// let [timestamp, value] = cache.get(key);
|
|
202
|
-
// if (Date.now() - timestamp < cacheTimeout) {
|
|
203
|
-
// return value;
|
|
204
|
-
// }
|
|
205
|
-
// }
|
|
206
|
-
// let result = originalMethod.apply(this, args);
|
|
207
|
-
// cache.set(key, [Date.now(), result]);
|
|
208
|
-
// return result;
|
|
209
|
-
// };
|
|
210
|
-
// return descriptor;
|
|
211
|
-
// };
|
|
212
|
-
// }
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { IUniswapV2Pair, PriceOracle } from '@aurigami/contracts/typechain';
|
|
2
|
-
import BigNumber from 'bignumber.js';
|
|
3
|
-
import { BigNumber as BN, providers } from 'ethers';
|
|
4
|
-
import { AuriOracleABI, IUniswapV2PairABI } from '../abis';
|
|
5
|
-
import { HARDCODE_PRICE_TOKENS, networkAddresses } from '../consts/constants';
|
|
6
|
-
import { Address } from '../types';
|
|
7
|
-
import { decimalFactor, devLog, getDecimal, isSameAddress } from './helpers';
|
|
8
|
-
import { createContract } from './multicall';
|
|
9
|
-
|
|
10
|
-
export async function fetchHistoricalLPPositions(
|
|
11
|
-
LPAddress: Address,
|
|
12
|
-
provider: providers.Provider,
|
|
13
|
-
block: number
|
|
14
|
-
): Promise<{
|
|
15
|
-
token0: Address;
|
|
16
|
-
token1: Address;
|
|
17
|
-
reserve0: BN;
|
|
18
|
-
reserve1: BN;
|
|
19
|
-
totalSupply: BN;
|
|
20
|
-
}> {
|
|
21
|
-
const LPContract = createContract<IUniswapV2Pair>(LPAddress, IUniswapV2PairABI.abi, provider);
|
|
22
|
-
var promises: any[] = [];
|
|
23
|
-
promises.push(LPContract.callStatic.token0());
|
|
24
|
-
promises.push(LPContract.callStatic.token1());
|
|
25
|
-
promises.push(LPContract.callStatic.getReserves({ blockTag: block }));
|
|
26
|
-
promises.push(LPContract.callStatic.totalSupply({ blockTag: block }));
|
|
27
|
-
const values: any[] = await Promise.all(promises);
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
token0: values[0] as string,
|
|
31
|
-
token1: values[1] as string,
|
|
32
|
-
reserve0: (values[2] as { reserve0: BN; reserve1: BN }).reserve0,
|
|
33
|
-
reserve1: (values[2] as { reserve0: BN; reserve1: BN }).reserve1,
|
|
34
|
-
totalSupply: values[3] as BN,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function fetchHistoricalLPPrice(
|
|
39
|
-
address: Address,
|
|
40
|
-
provider: providers.Provider,
|
|
41
|
-
block: number
|
|
42
|
-
): Promise<BigNumber> {
|
|
43
|
-
var LPInfo = await fetchHistoricalLPPositions(address, provider, block);
|
|
44
|
-
const LPDecimal = getDecimal(address);
|
|
45
|
-
|
|
46
|
-
async function fetchLPPriceBy(
|
|
47
|
-
tokenReverse: {
|
|
48
|
-
address: string;
|
|
49
|
-
reserve: BN;
|
|
50
|
-
},
|
|
51
|
-
block: number
|
|
52
|
-
): Promise<BigNumber> {
|
|
53
|
-
if (tokenReverse.reserve.isZero()) return new BigNumber(0);
|
|
54
|
-
|
|
55
|
-
const tokenPrice: BigNumber = await fetchHistoricalPrice(tokenReverse.address, provider, block);
|
|
56
|
-
const tokenDecimal = getDecimal(tokenReverse.address);
|
|
57
|
-
|
|
58
|
-
// reserveUSD will be divided by 10^tokenDecimal later for more precision
|
|
59
|
-
const reserveUSD: BigNumber = tokenPrice
|
|
60
|
-
.multipliedBy(tokenReverse.reserve.toString())
|
|
61
|
-
.multipliedBy(2);
|
|
62
|
-
return reserveUSD
|
|
63
|
-
.multipliedBy(decimalFactor(LPDecimal))
|
|
64
|
-
.dividedBy(new BigNumber(LPInfo.totalSupply.toString()))
|
|
65
|
-
.dividedBy(decimalFactor(tokenDecimal));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
// MUST await here
|
|
70
|
-
const lpPrice = await fetchLPPriceBy(
|
|
71
|
-
{
|
|
72
|
-
address: LPInfo.token0,
|
|
73
|
-
reserve: LPInfo.reserve0,
|
|
74
|
-
},
|
|
75
|
-
block
|
|
76
|
-
);
|
|
77
|
-
if (lpPrice.isZero()) {
|
|
78
|
-
throw Error(`Price is zero`);
|
|
79
|
-
}
|
|
80
|
-
return lpPrice;
|
|
81
|
-
} catch (e) {
|
|
82
|
-
devLog(`fetchLPPriceBy ${LPInfo.token0} failed`, e);
|
|
83
|
-
try {
|
|
84
|
-
// MUST await here
|
|
85
|
-
return await fetchLPPriceBy(
|
|
86
|
-
{
|
|
87
|
-
address: LPInfo.token1,
|
|
88
|
-
reserve: LPInfo.reserve1,
|
|
89
|
-
},
|
|
90
|
-
block
|
|
91
|
-
);
|
|
92
|
-
} catch (e) {
|
|
93
|
-
devLog(`fetchLPPriceBy ${LPInfo.token1} failed`, e);
|
|
94
|
-
throw Error(`Unable to fetch price for both tokens of LP ${address}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function processPriceFromOracle(rawPrice: BN, underlyingDecimal: number) {
|
|
100
|
-
return new BigNumber(rawPrice.toString()).div(decimalFactor(36 - underlyingDecimal));
|
|
101
|
-
}
|
|
102
|
-
export async function fetchHistoricalPriceFromOracle(
|
|
103
|
-
auTokenAddress: Address,
|
|
104
|
-
underlyingDecimal: number,
|
|
105
|
-
provider: providers.Provider,
|
|
106
|
-
block: number
|
|
107
|
-
): Promise<BigNumber> {
|
|
108
|
-
// from this block, we switch to use pyth
|
|
109
|
-
// TODO: add to consts
|
|
110
|
-
const oracleAddress =
|
|
111
|
-
block < 102438637
|
|
112
|
-
? networkAddresses.misc.DEPRECATED_OLD_ORACLE
|
|
113
|
-
: networkAddresses.misc.PYTH_ORACLE;
|
|
114
|
-
|
|
115
|
-
const oracleContract = createContract<PriceOracle>(oracleAddress, AuriOracleABI.abi, provider);
|
|
116
|
-
const rawPrice = await oracleContract.callStatic
|
|
117
|
-
.getUnderlyingPrice(auTokenAddress, { blockTag: block })
|
|
118
|
-
.catch((e: any) => {
|
|
119
|
-
console.log(`Unable to fetch price from oracle for ${auTokenAddress}`);
|
|
120
|
-
return BN.from(0);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
return processPriceFromOracle(rawPrice, underlyingDecimal);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export async function fetchHistoricalPrice(
|
|
127
|
-
address: Address,
|
|
128
|
-
provider: providers.Provider,
|
|
129
|
-
block: number
|
|
130
|
-
): Promise<BigNumber> {
|
|
131
|
-
if (address.toLowerCase() in HARDCODE_PRICE_TOKENS) {
|
|
132
|
-
return new BigNumber(HARDCODE_PRICE_TOKENS[address.toLowerCase()]);
|
|
133
|
-
} else if (
|
|
134
|
-
isSameAddress(address, networkAddresses.tokens.PLY_WNEAR) ||
|
|
135
|
-
isSameAddress(address, networkAddresses.tokens.WNEAR_TRI) ||
|
|
136
|
-
isSameAddress(address, networkAddresses.tokens.AURORA_WNEAR)
|
|
137
|
-
) {
|
|
138
|
-
return fetchHistoricalLPPrice(address, provider, block);
|
|
139
|
-
} else if (isSameAddress(address, networkAddresses.tokens.PLY)) {
|
|
140
|
-
return fetchHistoricalPriceByLP(networkAddresses.tokens.PLY_WNEAR, provider, block);
|
|
141
|
-
} else if (isSameAddress(address, networkAddresses.tokens.TRI)) {
|
|
142
|
-
return fetchHistoricalPriceByLP(networkAddresses.tokens.WNEAR_TRI, provider, block, 1);
|
|
143
|
-
} else if (isSameAddress(address, networkAddresses.tokens.AURORA)) {
|
|
144
|
-
return fetchHistoricalPriceByLP(networkAddresses.tokens.AURORA_WNEAR, provider, block);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const matchingAuToken = networkAddresses.auTokens.find((auToken) => {
|
|
148
|
-
return isSameAddress(auToken.underlying, address);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
if (matchingAuToken !== undefined) {
|
|
152
|
-
return fetchHistoricalPriceFromOracle(
|
|
153
|
-
matchingAuToken.address,
|
|
154
|
-
getDecimal(address),
|
|
155
|
-
provider,
|
|
156
|
-
block
|
|
157
|
-
);
|
|
158
|
-
} else {
|
|
159
|
-
throw Error(`Unable to fetch price for ${address}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export async function fetchHistoricalPULPPrice(provider: providers.Provider): Promise<BigNumber> {
|
|
164
|
-
//TODO: Calculate PULP price
|
|
165
|
-
return new BigNumber(0);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export async function fetchHistoricalPriceByLP(
|
|
169
|
-
LP: Address,
|
|
170
|
-
provider: providers.Provider,
|
|
171
|
-
block: number,
|
|
172
|
-
tokenNumber: 0 | 1 = 0
|
|
173
|
-
): Promise<BigNumber> {
|
|
174
|
-
let LPInfo = await fetchHistoricalLPPositions(LP, provider, block);
|
|
175
|
-
|
|
176
|
-
if (tokenNumber === 1) {
|
|
177
|
-
LPInfo = {
|
|
178
|
-
token0: LPInfo.token1,
|
|
179
|
-
token1: LPInfo.token0,
|
|
180
|
-
reserve0: LPInfo.reserve1,
|
|
181
|
-
reserve1: LPInfo.reserve0,
|
|
182
|
-
totalSupply: LPInfo.totalSupply,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (LPInfo.reserve1.isZero()) {
|
|
187
|
-
return new BigNumber(0);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const token0Decimal = getDecimal(LPInfo.token0);
|
|
191
|
-
const token1Decimal = getDecimal(LPInfo.token1);
|
|
192
|
-
|
|
193
|
-
// (token0Price * reserve0) / 10^decimal0 = (token1Price * reserve1) / 10^decimal1
|
|
194
|
-
// token0Price = (token1Price * reserve1) * 10^decimal0 / 10^decimal1 / reserve0
|
|
195
|
-
return (await fetchHistoricalPrice(LPInfo.token1, provider, block))
|
|
196
|
-
.multipliedBy(LPInfo.reserve1.toString())
|
|
197
|
-
.multipliedBy(decimalFactor(token0Decimal))
|
|
198
|
-
.dividedBy(decimalFactor(token1Decimal))
|
|
199
|
-
.dividedBy(LPInfo.reserve0.toString());
|
|
200
|
-
}
|
package/src/helpers/index.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
|
|
3
|
-
const KYBER_AGGREGATOR_AURORA_API_END_POINT =
|
|
4
|
-
'https://aggregator-api.kyberswap.com/aurora/route/encode';
|
|
5
|
-
|
|
6
|
-
const KYBER_AGGREGATOR_ETH_API_END_POINT =
|
|
7
|
-
'https://aggregator-api.kyberswap.com/ethereum/route/encode';
|
|
8
|
-
|
|
9
|
-
export async function getSwapInfo(
|
|
10
|
-
tokenIn: string,
|
|
11
|
-
tokenOut: string,
|
|
12
|
-
amountIn: string,
|
|
13
|
-
onAurora = true
|
|
14
|
-
): Promise<KyberApiResponse> {
|
|
15
|
-
const params = {
|
|
16
|
-
tokenIn,
|
|
17
|
-
tokenOut,
|
|
18
|
-
amountIn,
|
|
19
|
-
to: '0x0000000000000000000000000000000000000000',
|
|
20
|
-
useMeta: '1',
|
|
21
|
-
saveGas: '1',
|
|
22
|
-
gasInclude: '1',
|
|
23
|
-
};
|
|
24
|
-
const endpoint = onAurora
|
|
25
|
-
? KYBER_AGGREGATOR_AURORA_API_END_POINT
|
|
26
|
-
: KYBER_AGGREGATOR_ETH_API_END_POINT;
|
|
27
|
-
const resp = await axios.get(endpoint + '?' + new URLSearchParams(params), {
|
|
28
|
-
headers: { 'Content-Type': 'application/json' },
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return resp.data;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export type KyberApiResponse = {
|
|
35
|
-
inputAmount: string;
|
|
36
|
-
outputAmount: string;
|
|
37
|
-
};
|
package/src/helpers/multicall.ts
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import type { BlockTag } from '@ethersproject/abstract-provider';
|
|
2
|
-
import type { Provider } from '@ethersproject/providers';
|
|
3
|
-
|
|
4
|
-
import { CallOverrides, Contract, ContractInterface, Signer } from 'ethers';
|
|
5
|
-
import { FunctionFragment, Interface } from 'ethers/lib/utils';
|
|
6
|
-
import { Multicall2ABI } from '../abis';
|
|
7
|
-
import { MulticallOverrides, MulticallStatic } from '../types';
|
|
8
|
-
|
|
9
|
-
// export const MULTICALL_ADDRESSES: Record<ChainId, Address> = {
|
|
10
|
-
// [CHAIN_ID_MAPPING.ETHEREUM]: toAddress('0x5ba1e12693dc8f9c48aad8770482f4739beed696'),
|
|
11
|
-
// [CHAIN_ID_MAPPING.FUJI]: toAddress('0x07e46d95cc98f0d7493d679e89e396ea99020185'),
|
|
12
|
-
// [CHAIN_ID_MAPPING.MUMBAI]: toAddress('0x7De28d05a0781122565F3b49aA60331ced983a19'),
|
|
13
|
-
// [CHAIN_ID_MAPPING.ARBITRUM]: toAddress('0xcA11bde05977b3631167028862bE2a173976CA11'),
|
|
14
|
-
// } as const;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Multicall implementation, allowing to call function of contract.callStatic functions
|
|
18
|
-
* using multicall with Promise (without overrides).
|
|
19
|
-
*
|
|
20
|
-
* Example usage:
|
|
21
|
-
* const multicall = new Multicall({
|
|
22
|
-
* chainId,
|
|
23
|
-
* provider,
|
|
24
|
-
* });
|
|
25
|
-
* const contract = new Contract(address, PendleERC20ABI, networkConnection.provider) as PendleERC20;
|
|
26
|
-
*
|
|
27
|
-
* // very small interface changes
|
|
28
|
-
* const balance = await multicall.wrap(contract).callStatic.balanceOf(userAddress);
|
|
29
|
-
*
|
|
30
|
-
* // multiple calls
|
|
31
|
-
* const users = [addr1, addr2, addr3];
|
|
32
|
-
* const balances = await Promise.all(user.map((addr) => multicall.wrap(contract).callStatic.balanceOf(addr)));
|
|
33
|
-
*
|
|
34
|
-
* ### Result caching
|
|
35
|
-
* Multicall#wrap will cache the result right in the contract object. To access the cache result without
|
|
36
|
-
* calling the wrap function, use
|
|
37
|
-
*
|
|
38
|
-
* contract[multicall.multicallStaticSymbol]
|
|
39
|
-
*
|
|
40
|
-
* Note that the field `multicallStaticSymbol` is **not** static, but local to the multicall instance.
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
const TRANSFORMER = new Interface([]);
|
|
44
|
-
export const DEFAULT_CALL_LIMIT = 32;
|
|
45
|
-
|
|
46
|
-
class ContractCall {
|
|
47
|
-
fragment: FunctionFragment;
|
|
48
|
-
address: string;
|
|
49
|
-
params: any[];
|
|
50
|
-
|
|
51
|
-
constructor({
|
|
52
|
-
fragment,
|
|
53
|
-
address,
|
|
54
|
-
params,
|
|
55
|
-
}: {
|
|
56
|
-
fragment: FunctionFragment;
|
|
57
|
-
address: string;
|
|
58
|
-
params: any[];
|
|
59
|
-
}) {
|
|
60
|
-
this.fragment = fragment;
|
|
61
|
-
this.address = address;
|
|
62
|
-
this.params = params;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class Multicall {
|
|
67
|
-
static isMulticallOverrides(
|
|
68
|
-
overrides?: CallOverrides
|
|
69
|
-
): overrides is MulticallOverrides | undefined {
|
|
70
|
-
if (overrides === undefined) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
for (const key of Object.keys(overrides)) {
|
|
74
|
-
if (key !== 'blockTag' && (overrides as any)[key] != undefined) {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private multicallContract: Contract;
|
|
82
|
-
public readonly batchMap = new Map<BlockTag, MulticallBatch>();
|
|
83
|
-
readonly callLimit: number;
|
|
84
|
-
|
|
85
|
-
// Note: this symbol is unique for each Multicall instance
|
|
86
|
-
readonly multicallStaticSymbol = Symbol.for('multicallStatic');
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Perform _soft_ wrapping. If muticall is presented, multicall.wrap(contract) will be returned.
|
|
90
|
-
* Otherwise the contract itself will be returned. Note that this function is also type-safe,
|
|
91
|
-
* that is, even if the contract is returned, the user is disallowed to call functions
|
|
92
|
-
* with overrides.
|
|
93
|
-
*
|
|
94
|
-
* This function is useful in case where the user when to choose whether to use multicall
|
|
95
|
-
* by themselves.
|
|
96
|
-
*/
|
|
97
|
-
static wrap<T extends Contract>(
|
|
98
|
-
contract: T,
|
|
99
|
-
multicall: Multicall | undefined
|
|
100
|
-
): MulticallStatic<T> {
|
|
101
|
-
return multicall ? multicall.wrap(contract) : (contract as unknown as MulticallStatic<T>);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
constructor({
|
|
105
|
-
address,
|
|
106
|
-
provider,
|
|
107
|
-
callLimit,
|
|
108
|
-
}: {
|
|
109
|
-
address: string;
|
|
110
|
-
provider: Provider | Signer;
|
|
111
|
-
callLimit?: number;
|
|
112
|
-
}) {
|
|
113
|
-
this.multicallContract = new Contract(address, Multicall2ABI.abi, provider);
|
|
114
|
-
this.callLimit = callLimit ?? DEFAULT_CALL_LIMIT;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async doAggregateCalls(calls: readonly ContractCall[], blockTag: BlockTag) {
|
|
118
|
-
const callRequests = calls.map((call) => ({
|
|
119
|
-
target: call.address,
|
|
120
|
-
callData: TRANSFORMER.encodeFunctionData(call.fragment, call.params),
|
|
121
|
-
}));
|
|
122
|
-
|
|
123
|
-
const responses = await this.multicallContract.callStatic.tryAggregate(false, callRequests, {
|
|
124
|
-
blockTag: blockTag,
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const result = calls.map((call, i) => {
|
|
128
|
-
const [success, returnData] = responses[i];
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const outputs: any[] = call.fragment.outputs!;
|
|
132
|
-
const params = TRANSFORMER.decodeFunctionResult(call.fragment, returnData);
|
|
133
|
-
|
|
134
|
-
// If we do the !success check before the decode, we cannot get the error message of
|
|
135
|
-
// decodeFunctionResult. So we always decode first, then check the success later.
|
|
136
|
-
if (!success) {
|
|
137
|
-
const callId = FunctionFragment.from(call.fragment).format();
|
|
138
|
-
throw new Error(`Call ${call.address}:${callId} failed`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return outputs.length === 1 ? params[0] : params;
|
|
142
|
-
} catch (e: any) {
|
|
143
|
-
if (e.reason == null) {
|
|
144
|
-
e.reason = 'Call failed for unknown reason';
|
|
145
|
-
}
|
|
146
|
-
return e;
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
wrap<T extends Contract>(contract_: T): MulticallStatic<T> {
|
|
154
|
-
const contract = contract_ as T & { [key in symbol]: MulticallStatic<T> };
|
|
155
|
-
if (contract[this.multicallStaticSymbol]) {
|
|
156
|
-
return contract[this.multicallStaticSymbol];
|
|
157
|
-
}
|
|
158
|
-
const functions = contract_.interface.functions;
|
|
159
|
-
const funcs: Record<string, (...args: any[]) => Promise<any>> = {};
|
|
160
|
-
|
|
161
|
-
for (const [_, fn] of Object.entries(functions)) {
|
|
162
|
-
funcs[fn.name] = async (...params: any[]) => {
|
|
163
|
-
let blockTag: BlockTag = 'latest';
|
|
164
|
-
if (params.length === fn.inputs.length + 1) {
|
|
165
|
-
const overrides: MulticallOverrides = params.pop() ?? {};
|
|
166
|
-
if (!Multicall.isMulticallOverrides(overrides)) {
|
|
167
|
-
throw new Error('Overrides for multicall should contain only blockTag property');
|
|
168
|
-
}
|
|
169
|
-
blockTag = (await overrides.blockTag) ?? 'latest';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const contractCall = new ContractCall({
|
|
173
|
-
fragment: fn,
|
|
174
|
-
address: contract.address,
|
|
175
|
-
params,
|
|
176
|
-
});
|
|
177
|
-
const res = new Promise((resolve, reject) => {
|
|
178
|
-
let currentBatch = this.batchMap.get(blockTag);
|
|
179
|
-
if (currentBatch === undefined) {
|
|
180
|
-
currentBatch = new MulticallBatch(this, blockTag);
|
|
181
|
-
this.batchMap.set(blockTag, currentBatch);
|
|
182
|
-
}
|
|
183
|
-
const dataPos = currentBatch.pendingContractCalls.length;
|
|
184
|
-
currentBatch.pendingContractCalls.push(contractCall);
|
|
185
|
-
currentBatch.promise
|
|
186
|
-
.then((currentResult) =>
|
|
187
|
-
currentResult[dataPos] instanceof Error
|
|
188
|
-
? reject(currentResult[dataPos])
|
|
189
|
-
: resolve(currentResult[dataPos])
|
|
190
|
-
)
|
|
191
|
-
.catch(reject);
|
|
192
|
-
if (currentBatch.pendingContractCalls.length >= this.callLimit) {
|
|
193
|
-
this.batchMap.delete(blockTag);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return res;
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const res = {
|
|
202
|
-
callStatic: funcs,
|
|
203
|
-
address: contract.address,
|
|
204
|
-
raw: contract,
|
|
205
|
-
} as unknown as MulticallStatic<T>;
|
|
206
|
-
|
|
207
|
-
// Do this to avoid typescript error.
|
|
208
|
-
Object.assign(contract, { [this.multicallStaticSymbol]: res });
|
|
209
|
-
|
|
210
|
-
return res;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
class MulticallBatch {
|
|
215
|
-
readonly pendingContractCalls: ContractCall[] = [];
|
|
216
|
-
readonly promise: Promise<any[]>;
|
|
217
|
-
|
|
218
|
-
constructor(
|
|
219
|
-
private readonly multicallInstance: Multicall,
|
|
220
|
-
readonly blockTag: BlockTag = 'latest'
|
|
221
|
-
) {
|
|
222
|
-
this.promise = Promise.resolve().then(async () => {
|
|
223
|
-
// effects
|
|
224
|
-
|
|
225
|
-
// instance comparison
|
|
226
|
-
if (this.multicallInstance.batchMap.get(this.blockTag) === this) {
|
|
227
|
-
this.multicallInstance.batchMap.delete(this.blockTag);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// interactions
|
|
231
|
-
return this.multicallInstance.doAggregateCalls(this.pendingContractCalls, this.blockTag);
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
let multicall: Multicall | undefined;
|
|
237
|
-
|
|
238
|
-
export function createContract<T extends Contract>(
|
|
239
|
-
addressOrName: string,
|
|
240
|
-
contractInterface: ContractInterface,
|
|
241
|
-
signerOrProvider: Signer | Provider
|
|
242
|
-
) {
|
|
243
|
-
const contract = new Contract(addressOrName, contractInterface, signerOrProvider) as T;
|
|
244
|
-
if (!multicall) {
|
|
245
|
-
multicall = new Multicall({
|
|
246
|
-
address: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
|
247
|
-
provider: signerOrProvider,
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
return Multicall.wrap(contract, multicall);
|
|
251
|
-
}
|