Add liquidity / remove liquidity / balancee guard improvements

This commit is contained in:
Aleksandr Kraiz
2022-04-22 23:11:14 +04:00
parent 0a17972783
commit 0804b592d8
11 changed files with 467 additions and 61 deletions

View File

@@ -45,7 +45,7 @@ const env = "testing";
const startApp = async (provider: BaseProvider) => {
const web3provider = new providers.Web3Provider(provider);
await web3Provider.ready;
const signer = web3Provider.getSigner(account); // ready to go
const signer = web3Provider.getSigner(); // ready to go
const orionUnit = initOrionUnit(chain, env); // ready to go
};

View File

@@ -1,6 +1,6 @@
{
"name": "@orionprotocol/sdk",
"version": "0.2.4",
"version": "0.2.5",
"description": "Orion Protocol SDK",
"main": "lib/index.js",
"types": "lib/index.d.ts",

View File

@@ -6,6 +6,7 @@ import { APPROVE_ERC20_GAS_LIMIT, NATIVE_CURRENCY_PRECISION } from './constants'
import {
AggregatedBalanceRequirement, ApproveFix, Asset, BalanceIssue, BalanceRequirement, Source,
} from './types';
import { denormalizeNumber } from './utils';
import arrayEquals from './utils/arrayEquals';
export default class BalanceGuard {
@@ -13,7 +14,7 @@ export default class BalanceGuard {
Record<
string,
Record<
'exchange' | 'wallet' | 'allowance',
'exchange' | 'wallet',
BigNumber>
>
>;
@@ -27,7 +28,7 @@ export default class BalanceGuard {
private readonly signer: ethers.Signer;
constructor(
balances: Partial<Record<string, Record<'exchange' | 'wallet' | 'allowance', BigNumber>>>,
balances: Partial<Record<string, Record<'exchange' | 'wallet', BigNumber>>>,
nativeCryptocurrency: Asset,
provider: ethers.providers.Provider,
signer: ethers.Signer,
@@ -220,11 +221,24 @@ export default class BalanceGuard {
remainingBalance.exchange = remainingBalance.exchange.minus(itemsAmountSum);
if (remainingBalance.exchange.lt(0)) {
const lackAmount = remainingBalance.exchange.abs(); // e.g. -435.234234 to 434.234234
let denormalizedAllowance: BigNumber;
if (asset.address === ethers.constants.AddressZero) {
denormalizedAllowance = remainingBalance.wallet;
} else {
if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`);
const tokenContract = contracts.ERC20__factory.connect(asset.address, this.provider);
const tokenDecimals = await tokenContract.decimals();
const walletAddress = await this.signer.getAddress();
const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress);
denormalizedAllowance = denormalizeNumber(tokenAllowance, tokenDecimals);
}
// Try to take lack amount from wallet
const approvedWalletBalance = BigNumber
.min(
remainingBalance.wallet,
remainingBalance.allowance,
denormalizedAllowance,
// For native cryptocurrency allowance is always just current balance
);
if (lackAmount.lte(approvedWalletBalance)) { // We can take lack amount from wallet
@@ -302,10 +316,23 @@ export default class BalanceGuard {
if (!remainingBalance) throw new Error(`No ${asset.name} balance`);
const itemsAmountSum = Object.values(items)
.reduce<BigNumber>((p, c) => (c ? p.plus(c) : p), new BigNumber(0));
let denormalizedAllowance: BigNumber;
if (asset.address === ethers.constants.AddressZero) {
denormalizedAllowance = remainingBalance.wallet;
} else {
if (!spenderAddress) throw new Error(`Spender address is required for ${asset.name}`);
const tokenContract = contracts.ERC20__factory.connect(asset.address, this.provider);
const tokenDecimals = await tokenContract.decimals();
const walletAddress = await this.signer.getAddress();
const tokenAllowance = await tokenContract.allowance(walletAddress, spenderAddress);
denormalizedAllowance = denormalizeNumber(tokenAllowance, tokenDecimals);
}
const approvedWalletBalance = BigNumber
.min(
remainingBalance.wallet,
remainingBalance.allowance,
denormalizedAllowance,
);
if (itemsAmountSum.lte(approvedWalletBalance)) { // Approved wallet balance is enough
remainingBalance.wallet = remainingBalance.wallet.minus(itemsAmountSum);

View File

@@ -9,6 +9,7 @@ import {
DEPOSIT_ERC20_GAS_LIMIT, DEPOSIT_ETH_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION,
} from '../../constants';
import { normalizeNumber } from '../../utils';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
export type DepositParams = {
asset: string,
@@ -38,18 +39,8 @@ export default async function deposit({
exchangeContractAddress,
assetToAddress,
} = await orionBlockchain.getInfo();
const addressToAsset = Object
.entries(assetToAddress)
.reduce<Partial<Record<string, string>>>((prev, [assetName, address]) => {
if (!address) return prev;
return {
...prev,
[address]: assetName,
};
}, {});
const nativeCryptocurrency = addressToAsset[ethers.constants.AddressZero];
if (!nativeCryptocurrency) throw new Error('Native cryptocurrency asset is not found');
const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const exchangeContract = contracts.Exchange__factory.connect(exchangeContractAddress, provider);
const gasPriceWei = await orionBlockchain.getGasPriceWei();

View File

@@ -7,6 +7,7 @@ import getAvailableSources from '../../utils/getAvailableFundsSources';
import OrionUnit from '..';
import { contracts, crypt, utils } from '../..';
import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
export type SwapMarketParams = {
type: 'exactSpend' | 'exactReceive',
@@ -74,18 +75,7 @@ export default async function swapMarket({
matcherAddress,
assetToAddress,
} = await orionBlockchain.getInfo();
const addressToAsset = Object
.entries(assetToAddress)
.reduce<Partial<Record<string, string>>>((prev, [asset, address]) => {
if (!address) return prev;
return {
...prev,
[address]: asset,
};
}, {});
const nativeCryptocurrency = addressToAsset[ethers.constants.AddressZero];
if (!nativeCryptocurrency) throw new Error('Native cryptocurrency asset is not found');
const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const exchangeContract = contracts.Exchange__factory.connect(exchangeContractAddress, provider);
const feeAssets = await orionBlockchain.getTokensFee();

View File

@@ -9,6 +9,7 @@ import {
INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, WITHDRAW_GAS_LIMIT,
} from '../../constants';
import { normalizeNumber } from '../../utils';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
export type WithdrawParams = {
asset: string,
@@ -39,19 +40,7 @@ export default async function withdraw({
assetToAddress,
} = await orionBlockchain.getInfo();
const addressToAsset = Object
.entries(assetToAddress)
.reduce<Partial<Record<string, string>>>((prev, [assetName, address]) => {
if (!address) return prev;
return {
...prev,
[address]: assetName,
};
}, {});
const nativeCryptocurrency = addressToAsset[ethers.constants.AddressZero];
if (!nativeCryptocurrency) throw new Error('Native cryptocurrency asset is not found');
const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const exchangeContract = contracts.Exchange__factory.connect(exchangeContractAddress, provider);
const gasPriceWei = await orionBlockchain.getGasPriceWei();

View File

@@ -0,0 +1,405 @@
import BigNumber from 'bignumber.js';
import { ethers } from 'ethers';
import OrionUnit from '..';
import { contracts } from '../..';
import BalanceGuard from '../../BalanceGuard';
import { ADD_LIQUIDITY_GAS_LIMIT, INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION } from '../../constants';
import { denormalizeNumber, normalizeNumber } from '../../utils';
import getBalances from '../../utils/getBalances';
import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency';
const ADD_LIQUIDITY_SLIPPAGE = 0.05;
export type AddLiquidityParams = {
poolName: string,
amountAsset: string,
amount: BigNumber.Value,
signer: ethers.Signer
}
export type RemoveAllLiquidityParams = {
poolName: string,
signer: ethers.Signer
}
export default class FarmingManager {
private readonly orionUnit: OrionUnit;
constructor(orionUnit: OrionUnit) {
this.orionUnit = orionUnit;
}
public async addLiquidity({
poolName,
amountAsset,
amount,
signer,
}: AddLiquidityParams) {
const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error('Invalid amount');
if (amountBN.lte(0)) throw new Error('Amount must be greater than 0');
if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"');
const [assetA, assetB] = poolName.split('-');
if (amountAsset !== assetA && amountAsset !== assetB) throw new Error('Amount asset must be either assetA or assetB');
const {
exchangeContractAddress,
assetToAddress,
assetToDecimals,
} = await this.orionUnit.orionBlockchain.getInfo();
const walletAddress = await signer.getAddress();
const exchangeContract = contracts.Exchange__factory
.connect(exchangeContractAddress, this.orionUnit.provider);
const assetAAddress = assetToAddress[assetA];
if (!assetAAddress) throw new Error(`Asset '${assetA}' not found`);
const assetBAddress = assetToAddress[assetB];
if (!assetBAddress) throw new Error(`Asset '${assetB}' not found`);
const assetADecimals = assetToDecimals[assetA];
if (!assetADecimals) throw new Error(`Decimals for asset '${assetA}' not found`);
const assetBDecimals = assetToDecimals[assetB];
if (!assetBDecimals) throw new Error(`Decimals for asset '${assetB}' not found`);
const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const balances = await getBalances(
{
[assetA]: assetAAddress,
[assetB]: assetBAddress,
[nativeCryptocurrency]: ethers.constants.AddressZero,
},
this.orionUnit.orionAggregator,
walletAddress,
exchangeContract,
this.orionUnit.provider,
);
const balanceGuard = new BalanceGuard(
balances,
{
address: ethers.constants.AddressZero,
name: nativeCryptocurrency,
},
this.orionUnit.provider,
signer,
);
const poolsConfig = await this.orionUnit.orionBlockchain.getPoolsConfig();
const pool = poolsConfig.pools[poolName];
if (!pool) throw new Error(`Pool ${poolName} not found`);
const pairContract = contracts.IUniswapV2Pair__factory
.connect(pool.lpTokenAddress, this.orionUnit.provider);
const routerContract = contracts.IUniswapV2Router__factory
.connect(poolsConfig.routerAddress, this.orionUnit.provider);
let pairTokensIsInversed = false;
const token0 = await pairContract.token0();
const wrappedNativeAddress = await routerContract.WETH();
// const token1 = await pairContract.token1();
if (token0.toLowerCase() !== wrappedNativeAddress.toLowerCase()) pairTokensIsInversed = true;
const { _reserve0, _reserve1 } = await pairContract.getReserves();
const assetAReserve = pairTokensIsInversed ? _reserve1 : _reserve0;
const assetBReserve = pairTokensIsInversed ? _reserve0 : _reserve1;
const denormalizedAssetAReserve = denormalizeNumber(assetAReserve, assetADecimals);
const denormalizedAssetBReserve = denormalizeNumber(assetBReserve, assetBDecimals);
const price = denormalizedAssetBReserve.div(denormalizedAssetAReserve);
const assetAIsNativeCurrency = assetAAddress === ethers.constants.AddressZero;
const assetBIsNativeCurrency = assetBAddress === ethers.constants.AddressZero;
const assetAAmount = assetA === amountAsset ? amountBN : amountBN.div(price);
const assetBAmount = assetA === amountAsset ? amountBN.multipliedBy(price) : amountBN;
const assetAAmountWithSlippage = assetAAmount.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE);
const assetBAmountWithSlippage = assetBAmount.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE);
balanceGuard.registerRequirement({
reason: `${assetA} liquidity`,
amount: assetAAmount.toString(),
asset: {
name: assetA,
address: assetAAddress,
},
spenderAddress: exchangeContractAddress,
sources: ['exchange', 'wallet'],
});
balanceGuard.registerRequirement({
reason: `${assetB} liquidity`,
amount: assetBAmount.toString(),
asset: {
name: assetB,
address: assetBAddress,
},
spenderAddress: exchangeContractAddress,
sources: ['exchange', 'wallet'],
});
const unsignedTx = await exchangeContract?.populateTransaction.withdrawToPool(
assetBIsNativeCurrency ? assetBAddress : assetAAddress,
assetBIsNativeCurrency ? assetAAddress : assetBAddress,
assetBIsNativeCurrency
? normalizeNumber(assetBAmount, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR)
: normalizeNumber(assetAAmount, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR),
assetBIsNativeCurrency
? normalizeNumber(assetAAmount, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR)
: normalizeNumber(assetBAmount, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR),
assetBIsNativeCurrency
? normalizeNumber(assetBAmountWithSlippage, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR)
: normalizeNumber(assetAAmountWithSlippage, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR),
assetBIsNativeCurrency
? normalizeNumber(assetAAmountWithSlippage, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR)
: normalizeNumber(assetBAmountWithSlippage, INTERNAL_ORION_PRECISION, BigNumber.ROUND_FLOOR),
);
const gasPrice = await this.orionUnit.provider.getGasPrice();
const transactionCost = ethers.BigNumber.from(ADD_LIQUIDITY_GAS_LIMIT).mul(gasPrice);
const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION);
balanceGuard.registerRequirement({
reason: 'Network fee',
asset: {
name: nativeCryptocurrency,
address: ethers.constants.AddressZero,
},
amount: denormalizedTransactionCost.toString(),
sources: ['wallet'],
});
const nonce = await this.orionUnit.provider.getTransactionCount(walletAddress, 'pending');
const network = await this.orionUnit.provider.getNetwork();
if (assetAIsNativeCurrency || assetBIsNativeCurrency) {
const contractBalance = balances[nativeCryptocurrency]?.exchange;
if (!contractBalance) throw new Error(`No balance for '${nativeCryptocurrency}'`);
const nativeAssetAmount = assetBIsNativeCurrency ? assetBAmount : assetAAmount;
if (nativeAssetAmount.gt(contractBalance)) {
unsignedTx.value = normalizeNumber(
nativeAssetAmount.minus(contractBalance),
NATIVE_CURRENCY_PRECISION,
BigNumber.ROUND_CEIL,
);
}
}
unsignedTx.chainId = network.chainId;
unsignedTx.gasPrice = gasPrice;
unsignedTx.nonce = nonce;
unsignedTx.from = walletAddress;
const gasLimit = await this.orionUnit.provider.estimateGas(unsignedTx);
unsignedTx.gasLimit = gasLimit;
await balanceGuard.check(true);
const signedTx = await signer.signTransaction(unsignedTx);
const txResponse = await this.orionUnit.provider.sendTransaction(signedTx);
console.log(`Add liquidity tx sent: ${txResponse.hash}. Waiting for confirmation...`);
const txReceipt = await txResponse.wait();
if (txReceipt.status === 1) {
console.log(`Add liquidity tx confirmed: ${txReceipt.transactionHash}`);
} else {
console.log(`Add liquidity tx failed: ${txReceipt.transactionHash}`);
}
}
public async removeAllLiquidity({
poolName,
signer,
}: RemoveAllLiquidityParams) {
if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"');
const [assetA, assetB] = poolName.split('-');
const {
assetToAddress,
assetToDecimals,
exchangeContractAddress,
} = await this.orionUnit.orionBlockchain.getInfo();
const assetAAddress = assetToAddress[assetA];
if (!assetAAddress) throw new Error(`Asset '${assetA}' not found`);
const assetBAddress = assetToAddress[assetB];
if (!assetBAddress) throw new Error(`Asset '${assetB}' not found`);
const assetADecimals = assetToDecimals[assetA];
if (!assetADecimals) throw new Error(`Decimals for asset '${assetA}' not found`);
const assetBDecimals = assetToDecimals[assetB];
if (!assetBDecimals) throw new Error(`Decimals for asset '${assetB}' not found`);
const poolsConfig = await this.orionUnit.orionBlockchain.getPoolsConfig();
const pool = poolsConfig.pools[poolName];
if (!pool) throw new Error(`Pool ${poolName} not found`);
const walletAddress = await signer.getAddress();
const exchangeContract = contracts.Exchange__factory
.connect(exchangeContractAddress, this.orionUnit.provider);
const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress);
const balances = await getBalances(
{
[assetA]: assetAAddress,
[assetB]: assetBAddress,
[`${poolName} LP Token`]: pool.lpTokenAddress,
[nativeCryptocurrency]: ethers.constants.AddressZero,
},
this.orionUnit.orionAggregator,
walletAddress,
exchangeContract,
this.orionUnit.provider,
);
const balanceGuard = new BalanceGuard(
balances,
{
address: ethers.constants.AddressZero,
name: nativeCryptocurrency,
},
this.orionUnit.provider,
signer,
);
const pairContract = contracts.IUniswapV2Pair__factory
.connect(pool.lpTokenAddress, this.orionUnit.provider);
const { _reserve0, _reserve1 } = await pairContract.getReserves();
const routerContract = contracts.IUniswapV2Router__factory
.connect(poolsConfig.routerAddress, this.orionUnit.provider);
let pairTokensIsInversed = false;
const lpTokenUserBalance = await pairContract.balanceOf(walletAddress);
const lpTokenDecimals = await pairContract.decimals();
const token0 = await pairContract.token0();
const totalSupply = await pairContract.totalSupply();
const wrappedNativeAddress = await routerContract.WETH();
if (token0.toLowerCase() !== wrappedNativeAddress.toLowerCase()) pairTokensIsInversed = true;
const denormalizedLpTokenUserBalance = denormalizeNumber(lpTokenUserBalance, lpTokenDecimals);
const denormalizedLpTokenSupply = denormalizeNumber(totalSupply, lpTokenDecimals);
const userShare = denormalizedLpTokenUserBalance.div(denormalizedLpTokenSupply);
const assetAReserve = pairTokensIsInversed ? _reserve1 : _reserve0;
const assetBReserve = pairTokensIsInversed ? _reserve0 : _reserve1;
const denormalizedAssetAReserve = denormalizeNumber(assetAReserve, assetADecimals);
const denormalizedAssetBReserve = denormalizeNumber(assetBReserve, assetBDecimals);
const denormalizedUserPooledAssetA = denormalizedAssetAReserve.multipliedBy(userShare);
const denormalizedUserPooledAssetB = denormalizedAssetBReserve.multipliedBy(userShare);
const denormalizedUserPooledAssetAWithSlippage = denormalizedUserPooledAssetA.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE);
const denormalizedUserPooledAssetBWithSlippage = denormalizedUserPooledAssetB.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE);
const assetAIsNativeCurrency = assetAAddress === ethers.constants.AddressZero;
const assetBIsNativeCurrency = assetBAddress === ethers.constants.AddressZero;
balanceGuard.registerRequirement({
reason: `${poolName} liquidity`,
asset: {
name: `${poolName} LP Token`,
address: pool.lpTokenAddress,
},
spenderAddress: poolsConfig.routerAddress,
amount: denormalizedLpTokenUserBalance.toString(),
sources: ['wallet'],
});
let unsignedTx: ethers.PopulatedTransaction;
if (assetAIsNativeCurrency || assetBIsNativeCurrency) {
unsignedTx = await routerContract.populateTransaction.removeLiquidityETH(
assetBIsNativeCurrency ? assetAAddress : assetBAddress, // token
lpTokenUserBalance,
assetBIsNativeCurrency
? normalizeNumber(
denormalizedUserPooledAssetAWithSlippage,
assetADecimals,
BigNumber.ROUND_FLOOR,
)
: normalizeNumber(
denormalizedUserPooledAssetBWithSlippage,
assetBDecimals,
BigNumber.ROUND_FLOOR,
), // token min
assetBIsNativeCurrency
? normalizeNumber(
denormalizedUserPooledAssetBWithSlippage,
assetBDecimals,
BigNumber.ROUND_FLOOR,
)
: normalizeNumber(
denormalizedUserPooledAssetAWithSlippage,
assetADecimals,
BigNumber.ROUND_FLOOR,
), // eth min
walletAddress,
Math.floor(Date.now() / 1000) + 60 * 20,
);
} else {
unsignedTx = await routerContract.populateTransaction.removeLiquidity(
assetAAddress,
assetBAddress,
lpTokenUserBalance,
normalizeNumber(
denormalizedUserPooledAssetAWithSlippage,
assetADecimals,
BigNumber.ROUND_FLOOR,
),
normalizeNumber(
denormalizedUserPooledAssetBWithSlippage,
assetBDecimals,
BigNumber.ROUND_FLOOR,
),
walletAddress,
Math.floor(Date.now() / 1000) + 60 * 20,
);
}
const gasPrice = await this.orionUnit.provider.getGasPrice();
const transactionCost = ethers.BigNumber.from(ADD_LIQUIDITY_GAS_LIMIT).mul(gasPrice);
const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION);
balanceGuard.registerRequirement({
reason: 'Network fee',
asset: {
name: nativeCryptocurrency,
address: ethers.constants.AddressZero,
},
amount: denormalizedTransactionCost.toString(),
sources: ['wallet'],
});
await balanceGuard.check(true);
const nonce = await this.orionUnit.provider.getTransactionCount(walletAddress, 'pending');
const network = await this.orionUnit.provider.getNetwork();
unsignedTx.chainId = network.chainId;
unsignedTx.gasPrice = gasPrice;
unsignedTx.nonce = nonce;
unsignedTx.from = walletAddress;
const gasLimit = await this.orionUnit.provider.estimateGas(unsignedTx);
unsignedTx.gasLimit = gasLimit;
const signedTx = await signer.signTransaction(unsignedTx);
const txResponse = await this.orionUnit.provider.sendTransaction(signedTx);
console.log(`Remove all liquidity tx sent: ${txResponse.hash}. Waiting for confirmation...`);
const txReceipt = await txResponse.wait();
if (txReceipt.status === 1) {
console.log(`Remove all liquidity tx confirmed: ${txReceipt.transactionHash}`);
} else {
console.log(`Remove all liquidity tx failed: ${txReceipt.transactionHash}`);
}
}
}

View File

@@ -4,6 +4,7 @@ import { OrionBlockchain } from '../services/OrionBlockchain';
import { PriceFeed } from '../services/PriceFeed';
import { SupportedChainId } from '../types';
import Exchange from './Exchange';
import FarmingManager from './FarmingManager';
export default class OrionUnit {
public readonly env: string;
@@ -20,6 +21,8 @@ export default class OrionUnit {
public readonly exchange: Exchange;
public readonly farmingManager: FarmingManager;
public readonly apiUrl: string;
constructor(
@@ -37,5 +40,6 @@ export default class OrionUnit {
this.orionAggregator = new OrionAggregator(apiUrl, chainId);
this.priceFeed = new PriceFeed(apiUrl);
this.exchange = new Exchange(this);
this.farmingManager = new FarmingManager(this);
}
}

View File

@@ -15,43 +15,25 @@ export default async function getBalance(
const assetIsNativeCryptocurrency = assetAddress === ethers.constants.AddressZero;
let assetWalletBalance: ethers.BigNumber | undefined;
let assetAllowance: ethers.BigNumber | undefined;
let denormalizedAssetInWalletBalance: BigNumber | undefined;
let denormalizedAssetInAllowance: BigNumber | undefined;
if (!assetIsNativeCryptocurrency) {
const assetContract = contracts.ERC20__factory.connect(assetAddress, provider);
const assetDecimals = await assetContract.decimals();
assetWalletBalance = await assetContract.balanceOf(walletAddress);
assetAllowance = await assetContract.allowance(walletAddress, exchangeContract.address);
denormalizedAssetInWalletBalance = utils.denormalizeNumber(assetWalletBalance, assetDecimals);
denormalizedAssetInAllowance = utils.denormalizeNumber(assetAllowance, assetDecimals);
} else {
assetWalletBalance = await provider.getBalance(walletAddress);
denormalizedAssetInWalletBalance = utils.denormalizeNumber(assetWalletBalance, NATIVE_CURRENCY_PRECISION);
denormalizedAssetInAllowance = denormalizedAssetInWalletBalance; // For native crypto no allowance is needed
}
const assetContractBalance = await exchangeContract.getBalance(assetAddress, walletAddress);
const denormalizedAssetInContractBalance = utils.denormalizeNumber(assetContractBalance, INTERNAL_ORION_PRECISION);
// const denormalizedAssetWalletBalanceAvailable = BigNumber.min(denormalizedAssetInAllowance, denormalizedAssetInWalletBalance);
const denormalizedAssetLockedBalance = await orionAggregator.getLockedBalance(walletAddress, asset);
// const denormalizedAssetAvailableBalance = denormalizedAssetInContractBalance
// .plus(denormalizedAssetWalletBalanceAvailable)
// .minus(denormalizedAssetLockedBalance[asset] ?? 0);
// const denormalizedAssetImaginaryBalance = denormalizedAssetInContractBalance
// .plus(denormalizedAssetInWalletBalance)
// .minus(denormalizedAssetLockedBalance[asset] ?? 0);
return {
exchange: denormalizedAssetInContractBalance.minus(denormalizedAssetLockedBalance[asset] ?? 0),
// imaginary: denormalizedAssetImaginaryBalance,
wallet: denormalizedAssetInWalletBalance,
allowance: denormalizedAssetInAllowance,
// approvedWalletBalance: denormalizedAssetWalletBalanceAvailable,
// available: denormalizedAssetAvailableBalance,
// locked: denormalizedAssetLockedBalance[asset],
};
}

View File

@@ -33,7 +33,6 @@ export default async (
return balances.reduce<Partial<Record<string, {
exchange: BigNumber,
wallet: BigNumber,
allowance: BigNumber,
}>>>((prev, curr) => ({
...prev,
[curr.asset]: curr.amount,

View File

@@ -0,0 +1,19 @@
import { ethers } from 'ethers';
const getNativeCryptocurrency = (assetToAddress: Partial<Record<string, string>>) => {
const addressToAsset = Object
.entries(assetToAddress)
.reduce<Partial<Record<string, string>>>((prev, [asset, address]) => {
if (!address) return prev;
return {
...prev,
[address]: asset,
};
}, {});
const nativeCryptocurrency = addressToAsset[ethers.constants.AddressZero];
if (!nativeCryptocurrency) throw new Error('Native cryptocurrency asset is not found');
return nativeCryptocurrency;
};
export default getNativeCryptocurrency;