Files
orionprotocol-sdk/src/Unit/Exchange/deposit.ts
2023-05-16 23:21:45 +04:00

135 lines
4.2 KiB
TypeScript

import { BigNumber } from 'bignumber.js';
import { ethers } from 'ethers';
import { Exchange__factory } from '@orionprotocol/contracts/lib/ethers-v5/index.js';
import getBalances from '../../utils/getBalances.js';
import BalanceGuard from '../../BalanceGuard.js';
import type Unit from '../index.js';
import {
DEPOSIT_ERC20_GAS_LIMIT, DEPOSIT_ETH_GAS_LIMIT, INTERNAL_PROTOCOL_PRECISION, NATIVE_CURRENCY_PRECISION,
} from '../../constants/index.js';
import { denormalizeNumber, normalizeNumber } from '../../utils/index.js';
import getNativeCryptocurrencyName from '../../utils/getNativeCryptocurrencyName.js';
import { simpleFetch } from 'simple-typed-fetch';
export type DepositParams = {
asset: string
amount: BigNumber.Value
signer: ethers.Signer
unit: Unit
}
export default async function deposit({
asset,
amount,
signer,
unit,
}: DepositParams) {
if (asset === '') throw new Error('Asset can not be empty');
const amountBN = new BigNumber(amount);
if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`);
if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`);
const walletAddress = await signer.getAddress();
const {
blockchainService, aggregator, provider, chainId,
} = unit;
const {
exchangeContractAddress,
assetToAddress,
} = await simpleFetch(blockchainService.getInfo)();
const nativeCryptocurrency = getNativeCryptocurrencyName(assetToAddress);
const exchangeContract = Exchange__factory.connect(exchangeContractAddress, provider);
const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)();
const assetAddress = assetToAddress[asset];
if (assetAddress === undefined) throw new Error(`Asset '${asset}' not found`);
const balances = await getBalances(
{
[asset]: assetAddress,
[nativeCryptocurrency]: ethers.constants.AddressZero,
},
aggregator,
walletAddress,
exchangeContract,
provider,
);
const balanceGuard = new BalanceGuard(
balances,
{
name: nativeCryptocurrency,
address: ethers.constants.AddressZero,
},
provider,
signer,
);
balanceGuard.registerRequirement({
reason: 'Amount',
asset: {
name: asset,
address: assetAddress,
},
amount: amountBN.toString(),
spenderAddress: exchangeContractAddress,
sources: ['wallet'],
});
let unsignedTx: ethers.PopulatedTransaction;
if (asset === nativeCryptocurrency) {
unsignedTx = await exchangeContract.populateTransaction.deposit();
unsignedTx.value = normalizeNumber(amount, NATIVE_CURRENCY_PRECISION, BigNumber.ROUND_CEIL);
unsignedTx.gasLimit = ethers.BigNumber.from(DEPOSIT_ETH_GAS_LIMIT);
} else {
unsignedTx = await exchangeContract.populateTransaction.depositAsset(
assetAddress,
normalizeNumber(amount, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_CEIL),
);
unsignedTx.gasLimit = ethers.BigNumber.from(DEPOSIT_ERC20_GAS_LIMIT);
}
const transactionCost = ethers.BigNumber.from(unsignedTx.gasLimit).mul(gasPriceWei);
const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION);
balanceGuard.registerRequirement({
reason: 'Network fee',
asset: {
name: nativeCryptocurrency,
address: ethers.constants.AddressZero,
},
amount: denormalizedTransactionCost.toString(),
sources: ['wallet'],
});
unsignedTx.chainId = parseInt(chainId, 10);
unsignedTx.gasPrice = ethers.BigNumber.from(gasPriceWei);
unsignedTx.from = walletAddress;
await balanceGuard.check(true);
const nonce = await provider.getTransactionCount(walletAddress, 'pending');
unsignedTx.nonce = nonce;
const signedTx = await signer.signTransaction(unsignedTx);
try {
const txResponse = await provider.sendTransaction(signedTx);
console.log(`Deposit tx sent: ${txResponse.hash}. Waiting for confirmation...`);
const txReceipt = await txResponse.wait();
if (txReceipt.status !== undefined) {
console.log('Deposit tx confirmed');
} else {
console.log('Deposit tx failed');
}
} catch (e) {
if (!(e instanceof Error)) throw new Error('e is not an Error');
console.error(`Deposit tx failed: ${e.message}`, {
unsignedTx,
});
}
}