@evolutionland/evolution-js
Version:
evolution evolution-js evolutionland evolution-js-sdk evolution-land metaverse
189 lines (188 loc) • 10.1 kB
JavaScript
import { Token, Price, TokenAmount, InsufficientReservesError, InsufficientInputAmountError } from "../../libs/uniswap";
import invariant from "tiny-invariant";
import JSBI from "jsbi";
import { pack, keccak256 } from "@ethersproject/solidity";
import { getCreate2Address } from "@ethersproject/address";
import { sqrt, parseBigintIsh } from "./uniswapUtils";
import { MINIMUM_LIQUIDITY } from "../../libs/uniswap";
var ZERO = /*#__PURE__*/ JSBI.BigInt(0);
var ONE = /*#__PURE__*/ JSBI.BigInt(1);
var FIVE = /*#__PURE__*/ JSBI.BigInt(5);
var _997 = /*#__PURE__*/ JSBI.BigInt(997);
var _1000 = /*#__PURE__*/ JSBI.BigInt(1000);
let PAIR_ADDRESS_CACHE = {
// '0x2f6aE7fDbB7c0c613F7923Ddce3E5b71aFE71f78': {
// '0xD4C2F962B8b94cdD2e0B2e8E765d39f32980a1c1': '0x5a5B56EE7F615Ca4f9676703f9aB8AD4C4954092'
// }
};
const FACTORY_ADDRESS = {
1: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
3: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
44: "0x36ABF1A7851fBF9ae9D79dc3E39C1227068158B3",
56: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",
97: "0x6725F303b657a9451d8BA641348b6761A6CC7a17",
128: "0xb0b670fc1F7724119963018DB0BfA86aDb22d941",
137: "0x5757371414417b8c6caad45baef941abc7d3ab32",
256: "0xA19a691EB6dE729758BFCef165e117C830483eF0",
80001: "0x6d7cdf98a49f968F6eB90eEb3D8189038760d439",
};
// https://github.com/Uniswap/uniswap-v2-core/issues/102
// We can use create LP to calculate the hash using the generated lp contract bytescode. UniswapV2Pair contract
const INIT_CODE_HASH = {
1: "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f",
3: "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f",
44: "0x2a3eebed007578fadb94fc416a8002f6bcef7ee2aae9680a5616e2fb4e407a51",
56: "0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5",
97: "0xd0d4c4cd0848c93cb4fd1f498d7013ee6bfb25783ea21593d5834f5d250ece66",
128: "0x2ad889f82040abccb2649ea6a874796c1601fb67f91a747a80e08860c73ddf24",
137: "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f",
256: "0x6fcc083b512761e9f65d41be84dbc66f5afb698ad320a8b0e1e6d2d0e4d10930",
80001: "0x6fcc083b512761e9f65d41be84dbc66f5afb698ad320a8b0e1e6d2d0e4d10930",
};
export class Pair {
static getAddress(tokenA, tokenB) {
var _a;
const tokens = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]; // does safety checks
if (((_a = PAIR_ADDRESS_CACHE === null || PAIR_ADDRESS_CACHE === void 0 ? void 0 : PAIR_ADDRESS_CACHE[tokens[0].address]) === null || _a === void 0 ? void 0 : _a[tokens[1].address]) === undefined) {
PAIR_ADDRESS_CACHE = Object.assign(Object.assign({}, PAIR_ADDRESS_CACHE), { [tokens[0].address]: Object.assign(Object.assign({}, PAIR_ADDRESS_CACHE === null || PAIR_ADDRESS_CACHE === void 0 ? void 0 : PAIR_ADDRESS_CACHE[tokens[0].address]), { [tokens[1].address]: getCreate2Address(FACTORY_ADDRESS[tokens[0].chainId], keccak256(["bytes"], [pack(["address", "address"], [tokens[0].address, tokens[1].address])]), INIT_CODE_HASH[tokens[0].chainId]) }) });
}
return PAIR_ADDRESS_CACHE[tokens[0].address][tokens[1].address];
}
constructor(tokenAmountA, tokenAmountB) {
const tokenAmounts = tokenAmountA.token.sortsBefore(tokenAmountB.token) // does safety checks
? [tokenAmountA, tokenAmountB]
: [tokenAmountB, tokenAmountA];
this.liquidityToken = new Token(tokenAmounts[0].token.chainId, Pair.getAddress(tokenAmounts[0].token, tokenAmounts[1].token), 18, "UNI-V2", "Uniswap V2");
this.tokenAmounts = tokenAmounts;
}
/**
* Returns true if the token is either token0 or token1
* @param token to check
*/
involvesToken(token) {
return token.equals(this.token0) || token.equals(this.token1);
}
/**
* Returns the current mid price of the pair in terms of token0, i.e. the ratio of reserve1 to reserve0
*/
get token0Price() {
return new Price(this.token0, this.token1, this.tokenAmounts[0].raw, this.tokenAmounts[1].raw);
}
/**
* Returns the current mid price of the pair in terms of token1, i.e. the ratio of reserve0 to reserve1
*/
get token1Price() {
return new Price(this.token1, this.token0, this.tokenAmounts[1].raw, this.tokenAmounts[0].raw);
}
/**
* Return the price of the given token in terms of the other token in the pair.
* @param token token to return price of
*/
priceOf(token) {
invariant(this.involvesToken(token), "TOKEN");
return token.equals(this.token0) ? this.token0Price : this.token1Price;
}
/**
* Returns the chain ID of the tokens in the pair.
*/
get chainId() {
return this.token0.chainId;
}
get token0() {
return this.tokenAmounts[0].token;
}
get token1() {
return this.tokenAmounts[1].token;
}
get reserve0() {
return this.tokenAmounts[0];
}
get reserve1() {
return this.tokenAmounts[1];
}
reserveOf(token) {
invariant(this.involvesToken(token), "TOKEN");
return token.equals(this.token0) ? this.reserve0 : this.reserve1;
}
getOutputAmount(inputAmount) {
invariant(this.involvesToken(inputAmount.token), "TOKEN");
if (JSBI.equal(this.reserve0.raw, ZERO) || JSBI.equal(this.reserve1.raw, ZERO)) {
throw new InsufficientReservesError();
}
const inputReserve = this.reserveOf(inputAmount.token);
const outputReserve = this.reserveOf(inputAmount.token.equals(this.token0) ? this.token1 : this.token0);
const inputAmountWithFee = JSBI.multiply(inputAmount.raw, _997);
const numerator = JSBI.multiply(inputAmountWithFee, outputReserve.raw);
const denominator = JSBI.add(JSBI.multiply(inputReserve.raw, _1000), inputAmountWithFee);
const outputAmount = new TokenAmount(inputAmount.token.equals(this.token0) ? this.token1 : this.token0, JSBI.divide(numerator, denominator));
if (JSBI.equal(outputAmount.raw, ZERO)) {
throw new InsufficientInputAmountError();
}
return [outputAmount, new Pair(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))];
}
getInputAmount(outputAmount) {
invariant(this.involvesToken(outputAmount.token), "TOKEN");
if (JSBI.equal(this.reserve0.raw, ZERO) ||
JSBI.equal(this.reserve1.raw, ZERO) ||
JSBI.greaterThanOrEqual(outputAmount.raw, this.reserveOf(outputAmount.token).raw)) {
throw new InsufficientReservesError();
}
const outputReserve = this.reserveOf(outputAmount.token);
const inputReserve = this.reserveOf(outputAmount.token.equals(this.token0) ? this.token1 : this.token0);
const numerator = JSBI.multiply(JSBI.multiply(inputReserve.raw, outputAmount.raw), _1000);
const denominator = JSBI.multiply(JSBI.subtract(outputReserve.raw, outputAmount.raw), _997);
const inputAmount = new TokenAmount(outputAmount.token.equals(this.token0) ? this.token1 : this.token0, JSBI.add(JSBI.divide(numerator, denominator), ONE));
return [inputAmount, new Pair(inputReserve.add(inputAmount), outputReserve.subtract(outputAmount))];
}
getLiquidityMinted(totalSupply, tokenAmountA, tokenAmountB) {
invariant(totalSupply.token.equals(this.liquidityToken), "LIQUIDITY");
const tokenAmounts = tokenAmountA.token.sortsBefore(tokenAmountB.token) // does safety checks
? [tokenAmountA, tokenAmountB]
: [tokenAmountB, tokenAmountA];
invariant(tokenAmounts[0].token.equals(this.token0) && tokenAmounts[1].token.equals(this.token1), "TOKEN");
let liquidity;
if (JSBI.equal(totalSupply.raw, ZERO)) {
liquidity = JSBI.subtract(sqrt(JSBI.multiply(tokenAmounts[0].raw, tokenAmounts[1].raw)), MINIMUM_LIQUIDITY);
}
else {
const amount0 = JSBI.divide(JSBI.multiply(tokenAmounts[0].raw, totalSupply.raw), this.reserve0.raw);
const amount1 = JSBI.divide(JSBI.multiply(tokenAmounts[1].raw, totalSupply.raw), this.reserve1.raw);
liquidity = JSBI.lessThanOrEqual(amount0, amount1) ? amount0 : amount1;
}
if (!JSBI.greaterThan(liquidity, ZERO)) {
throw new InsufficientInputAmountError();
}
return new TokenAmount(this.liquidityToken, liquidity);
}
getLiquidityValue(token, totalSupply, liquidity, feeOn = false, kLast) {
invariant(this.involvesToken(token), "TOKEN");
invariant(totalSupply.token.equals(this.liquidityToken), "TOTAL_SUPPLY");
invariant(liquidity.token.equals(this.liquidityToken), "LIQUIDITY");
invariant(JSBI.lessThanOrEqual(liquidity.raw, totalSupply.raw), "LIQUIDITY");
let totalSupplyAdjusted;
if (!feeOn) {
totalSupplyAdjusted = totalSupply;
}
else {
invariant(!!kLast, "K_LAST");
const kLastParsed = parseBigintIsh(kLast);
if (!JSBI.equal(kLastParsed, ZERO)) {
const rootK = sqrt(JSBI.multiply(this.reserve0.raw, this.reserve1.raw));
const rootKLast = sqrt(kLastParsed);
if (JSBI.greaterThan(rootK, rootKLast)) {
const numerator = JSBI.multiply(totalSupply.raw, JSBI.subtract(rootK, rootKLast));
const denominator = JSBI.add(JSBI.multiply(rootK, FIVE), rootKLast);
const feeLiquidity = JSBI.divide(numerator, denominator);
totalSupplyAdjusted = totalSupply.add(new TokenAmount(this.liquidityToken, feeLiquidity));
}
else {
totalSupplyAdjusted = totalSupply;
}
}
else {
totalSupplyAdjusted = totalSupply;
}
}
return new TokenAmount(token, JSBI.divide(JSBI.multiply(liquidity.raw, this.reserveOf(token).raw), totalSupplyAdjusted.raw));
}
}