mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-14 06:02:36 +03:00
Merge pull request #218 from orionprotocol/fix/returnEthValue
Fix/return eth value
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@orionprotocol/sdk",
|
||||
"version": "0.20.26",
|
||||
"version": "0.20.26-rc3",
|
||||
"description": "Orion Protocol SDK",
|
||||
"main": "./lib/index.cjs",
|
||||
"module": "./lib/index.js",
|
||||
|
||||
@@ -1,73 +1,72 @@
|
||||
import type { LibValidator } from '@orionprotocol/contracts/lib/ethers-v6/Exchange.js';
|
||||
import { ethers, ZeroAddress } from 'ethers';
|
||||
import type { AddressLike, JsonRpcProvider, BigNumberish, BytesLike } from 'ethers';
|
||||
import cloneDeep from 'lodash.clonedeep';
|
||||
import { safeGet, SafeArray } from '../../utils/safeGetters.js';
|
||||
import { simpleFetch } from 'simple-typed-fetch';
|
||||
import type Unit from '../index.js';
|
||||
import { generateUni2Calls, generateUni2Call } from './callGenerators/uniswapV2.js';
|
||||
import type { LibValidator } from "@orionprotocol/contracts/lib/ethers-v6/Exchange.js";
|
||||
import { ethers, ZeroAddress } from "ethers";
|
||||
import type { AddressLike, JsonRpcProvider, BigNumberish, BytesLike } from "ethers";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { safeGet, SafeArray } from "../../utils/safeGetters.js";
|
||||
import { simpleFetch } from "simple-typed-fetch";
|
||||
import type Unit from "../index.js";
|
||||
import { generateUni2Calls, generateUni2Call } from "./callGenerators/uniswapV2.js";
|
||||
import {
|
||||
generateUni3Calls,
|
||||
generateOrion3Calls,
|
||||
generateUni3Call,
|
||||
generateOrion3Call,
|
||||
} from './callGenerators/uniswapV3.js';
|
||||
import { exchangeToNativeDecimals, generateCalls, pathCallWithBalance } from './callGenerators/utils.js';
|
||||
import { generateTransferCall } from './callGenerators/erc20.js';
|
||||
import { generateCurveStableSwapCall } from './callGenerators/curve.js';
|
||||
import type { SingleSwap } from '../../types.js';
|
||||
import { addressLikeToString } from '../../utils/addressLikeToString.js';
|
||||
import { generateUnwrapAndTransferCall, generateWrapAndTransferCall } from './callGenerators/weth.js';
|
||||
import { getWalletBalance } from '../../utils/getBalance.js';
|
||||
} from "./callGenerators/uniswapV3.js";
|
||||
import { exchangeToNativeDecimals, generateCalls, pathCallWithBalance } from "./callGenerators/utils.js";
|
||||
import { generateTransferCall } from "./callGenerators/erc20.js";
|
||||
import { generateCurveStableSwapCall } from "./callGenerators/curve.js";
|
||||
import type { SingleSwap } from "../../types.js";
|
||||
import { addressLikeToString } from "../../utils/addressLikeToString.js";
|
||||
import { generateUnwrapAndTransferCall, generateWrapAndTransferCall } from "./callGenerators/weth.js";
|
||||
import { getExchangeBalance, getWalletBalance } from "../../utils/getBalance.js";
|
||||
|
||||
export type Factory = 'UniswapV2' | 'UniswapV3' | 'Curve' | 'OrionV2' | 'OrionV3';
|
||||
export type Factory = "UniswapV2" | "UniswapV3" | "Curve" | "OrionV2" | "OrionV3";
|
||||
|
||||
export type GenerateSwapCalldataWithUnitParams = {
|
||||
amount: BigNumberish
|
||||
minReturnAmount: BigNumberish
|
||||
receiverAddress: string
|
||||
path: ArrayLike<SingleSwap>
|
||||
unit: Unit
|
||||
amount: BigNumberish;
|
||||
minReturnAmount: BigNumberish;
|
||||
initiatorAddress: string;
|
||||
receiverAddress: string;
|
||||
path: ArrayLike<SingleSwap>;
|
||||
unit: Unit;
|
||||
};
|
||||
|
||||
export type GenerateSwapCalldataParams = {
|
||||
amount: BigNumberish
|
||||
minReturnAmount: BigNumberish
|
||||
receiverAddress: string
|
||||
useContractBalance: boolean
|
||||
path: ArrayLike<SingleSwap>
|
||||
wethAddress: AddressLike
|
||||
curveRegistryAddress: AddressLike
|
||||
swapExecutorContractAddress: AddressLike
|
||||
provider: JsonRpcProvider
|
||||
amount: BigNumberish;
|
||||
minReturnAmount: BigNumberish;
|
||||
initiatorAddress: string;
|
||||
receiverAddress: string;
|
||||
path: ArrayLike<SingleSwap>;
|
||||
exchangeContractAddress: AddressLike;
|
||||
wethAddress: AddressLike;
|
||||
curveRegistryAddress: AddressLike;
|
||||
swapExecutorContractAddress: AddressLike;
|
||||
provider: JsonRpcProvider;
|
||||
};
|
||||
|
||||
export async function generateSwapCalldataWithUnit({
|
||||
amount,
|
||||
minReturnAmount,
|
||||
initiatorAddress,
|
||||
receiverAddress,
|
||||
path: arrayLikePath,
|
||||
unit,
|
||||
}: GenerateSwapCalldataWithUnitParams): Promise<{
|
||||
calldata: string
|
||||
swapDescription: LibValidator.SwapDescriptionStruct
|
||||
calldata: string;
|
||||
swapDescription: LibValidator.SwapDescriptionStruct;
|
||||
value: bigint;
|
||||
}> {
|
||||
if (arrayLikePath == undefined || arrayLikePath.length == 0) {
|
||||
throw new Error('Empty path');
|
||||
throw new Error("Empty path");
|
||||
}
|
||||
const wethAddress = safeGet(unit.contracts, 'WETH');
|
||||
const curveRegistryAddress = safeGet(unit.contracts, 'curveRegistry');
|
||||
const { assetToAddress, swapExecutorContractAddress } = await simpleFetch(
|
||||
const wethAddress = safeGet(unit.contracts, "WETH");
|
||||
const curveRegistryAddress = safeGet(unit.contracts, "curveRegistry");
|
||||
const { assetToAddress, swapExecutorContractAddress, exchangeContractAddress } = await simpleFetch(
|
||||
unit.blockchainService.getInfo
|
||||
)();
|
||||
|
||||
const arrayLikePathCopy = cloneDeep(arrayLikePath);
|
||||
let path = SafeArray.from(arrayLikePathCopy);
|
||||
const walletBalance = await getWalletBalance(
|
||||
assetToAddress[path.first().assetIn] ?? path.first().assetIn.toLowerCase(),
|
||||
receiverAddress,
|
||||
unit.provider
|
||||
);
|
||||
|
||||
path = SafeArray.from(arrayLikePathCopy).map((swapInfo) => {
|
||||
swapInfo.assetIn = assetToAddress[swapInfo.assetIn] ?? swapInfo.assetIn.toLowerCase();
|
||||
@@ -79,8 +78,9 @@ export async function generateSwapCalldataWithUnit({
|
||||
amount,
|
||||
minReturnAmount,
|
||||
receiverAddress,
|
||||
useContractBalance: walletBalance < await exchangeToNativeDecimals(path.first().assetIn, amount, unit.provider),
|
||||
initiatorAddress,
|
||||
path,
|
||||
exchangeContractAddress,
|
||||
wethAddress,
|
||||
curveRegistryAddress,
|
||||
swapExecutorContractAddress,
|
||||
@@ -91,21 +91,26 @@ export async function generateSwapCalldataWithUnit({
|
||||
export async function generateSwapCalldata({
|
||||
amount,
|
||||
minReturnAmount,
|
||||
initiatorAddress,
|
||||
receiverAddress,
|
||||
useContractBalance,
|
||||
path: arrayLikePath,
|
||||
exchangeContractAddress,
|
||||
wethAddress: wethAddressLike,
|
||||
curveRegistryAddress: curveRegistryAddressLike,
|
||||
swapExecutorContractAddress: swapExecutorContractAddressLike,
|
||||
provider,
|
||||
}: GenerateSwapCalldataParams) {
|
||||
}: GenerateSwapCalldataParams): Promise<{
|
||||
calldata: string;
|
||||
swapDescription: LibValidator.SwapDescriptionStruct;
|
||||
value: bigint;
|
||||
}> {
|
||||
const wethAddress = await addressLikeToString(wethAddressLike);
|
||||
const curveRegistryAddress = await addressLikeToString(curveRegistryAddressLike);
|
||||
const swapExecutorContractAddress = await addressLikeToString(swapExecutorContractAddressLike);
|
||||
let path = SafeArray.from(arrayLikePath);
|
||||
|
||||
const { factory, assetIn: srcToken } = path.first();
|
||||
const dstToken = path.last().assetOut;
|
||||
const { assetOut: dstToken } = path.last();
|
||||
|
||||
let swapDescription: LibValidator.SwapDescriptionStruct = {
|
||||
srcToken,
|
||||
@@ -156,11 +161,25 @@ export async function generateSwapCalldata({
|
||||
));
|
||||
const calldata = generateCalls(calls);
|
||||
|
||||
if (useContractBalance) {
|
||||
const initiatorWalletBalance = await getWalletBalance(srcToken, initiatorAddress, provider);
|
||||
const initiatorExchangeBalance = await getExchangeBalance(
|
||||
srcToken,
|
||||
initiatorAddress,
|
||||
exchangeContractAddress,
|
||||
provider,
|
||||
true
|
||||
);
|
||||
const useExchangeBalance =
|
||||
initiatorExchangeBalance !== 0n && (srcToken === ZeroAddress || initiatorWalletBalance < amountNativeDecimals);
|
||||
if (useExchangeBalance) {
|
||||
swapDescription.flags = 1n << 255n;
|
||||
}
|
||||
let value = 0n;
|
||||
if (srcToken === ZeroAddress && initiatorExchangeBalance < amountNativeDecimals) {
|
||||
value = amountNativeDecimals - initiatorExchangeBalance;
|
||||
}
|
||||
|
||||
return { swapDescription, calldata };
|
||||
return { swapDescription, calldata, value };
|
||||
}
|
||||
|
||||
async function processSingleFactorySwaps(
|
||||
@@ -174,27 +193,27 @@ async function processSingleFactorySwaps(
|
||||
) {
|
||||
let calls: BytesLike[] = [];
|
||||
switch (factory) {
|
||||
case 'OrionV2': {
|
||||
case "OrionV2": {
|
||||
swapDescription.srcReceiver = path.first().pool;
|
||||
calls = await generateUni2Calls(path, swapExecutorContractAddress);
|
||||
break;
|
||||
}
|
||||
case 'UniswapV2': {
|
||||
case "UniswapV2": {
|
||||
swapDescription.srcReceiver = path.first().pool;
|
||||
calls = await generateUni2Calls(path, swapExecutorContractAddress);
|
||||
break;
|
||||
}
|
||||
case 'UniswapV3': {
|
||||
case "UniswapV3": {
|
||||
calls = await generateUni3Calls(path, amount, swapExecutorContractAddress, provider);
|
||||
break;
|
||||
}
|
||||
case 'OrionV3': {
|
||||
case "OrionV3": {
|
||||
calls = await generateOrion3Calls(path, amount, swapExecutorContractAddress, provider);
|
||||
break;
|
||||
}
|
||||
case 'Curve': {
|
||||
case "Curve": {
|
||||
if (path.length > 1) {
|
||||
throw new Error('Supporting only single stable swap on curve');
|
||||
throw new Error("Supporting only single stable swap on curve");
|
||||
}
|
||||
calls = await generateCurveStableSwapCall(
|
||||
amount,
|
||||
@@ -224,33 +243,33 @@ async function processMultiFactorySwaps(
|
||||
let calls: BytesLike[] = [];
|
||||
for (const swap of path) {
|
||||
switch (swap.factory) {
|
||||
case 'OrionV2': {
|
||||
case "OrionV2": {
|
||||
let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0);
|
||||
transferCall = pathCallWithBalance(transferCall, swap.assetIn);
|
||||
const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress);
|
||||
calls.push(transferCall, uni2Call);
|
||||
break;
|
||||
}
|
||||
case 'UniswapV2': {
|
||||
case "UniswapV2": {
|
||||
let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0);
|
||||
transferCall = pathCallWithBalance(transferCall, swap.assetIn);
|
||||
const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress);
|
||||
calls.push(transferCall, uni2Call);
|
||||
break;
|
||||
}
|
||||
case 'UniswapV3': {
|
||||
case "UniswapV3": {
|
||||
let uni3Call = await generateUni3Call(swap, 0, swapExecutorContractAddress, provider);
|
||||
uni3Call = pathCallWithBalance(uni3Call, swap.assetIn);
|
||||
calls.push(uni3Call);
|
||||
break;
|
||||
}
|
||||
case 'OrionV3': {
|
||||
case "OrionV3": {
|
||||
let orion3Call = await generateOrion3Call(swap, 0, swapExecutorContractAddress, provider);
|
||||
orion3Call = pathCallWithBalance(orion3Call, swap.assetIn);
|
||||
calls.push(orion3Call);
|
||||
break;
|
||||
}
|
||||
case 'Curve': {
|
||||
case "Curve": {
|
||||
let curveCalls = await generateCurveStableSwapCall(
|
||||
amount,
|
||||
swapExecutorContractAddress,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { ERC20__factory, type Exchange } from '@orionprotocol/contracts/lib/ethers-v6/index.js';
|
||||
import type { BigNumber } from 'bignumber.js';
|
||||
import { ethers } from 'ethers';
|
||||
import { INTERNAL_PROTOCOL_PRECISION, NATIVE_CURRENCY_PRECISION } from '../constants/index.js';
|
||||
import type { Aggregator } from '../services/Aggregator/index.js';
|
||||
import denormalizeNumber from './denormalizeNumber.js';
|
||||
import { ERC20__factory, Exchange__factory, type Exchange } from "@orionprotocol/contracts/lib/ethers-v6/index.js";
|
||||
import type { BigNumber } from "bignumber.js";
|
||||
import { ZeroAddress, ethers } from "ethers";
|
||||
import { INTERNAL_PROTOCOL_PRECISION, NATIVE_CURRENCY_PRECISION } from "../constants/index.js";
|
||||
import type { Aggregator } from "../services/Aggregator/index.js";
|
||||
import denormalizeNumber from "./denormalizeNumber.js";
|
||||
import type { AddressLike } from "ethers";
|
||||
import { addressLikeToString } from "./addressLikeToString.js";
|
||||
|
||||
export default async function getBalance(
|
||||
aggregator: Aggregator,
|
||||
@@ -11,7 +13,7 @@ export default async function getBalance(
|
||||
assetAddress: string,
|
||||
walletAddress: string,
|
||||
exchangeContract: Exchange,
|
||||
provider: ethers.Provider,
|
||||
provider: ethers.Provider
|
||||
) {
|
||||
const assetIsNativeCryptocurrency = assetAddress === ethers.ZeroAddress;
|
||||
|
||||
@@ -30,7 +32,10 @@ export default async function getBalance(
|
||||
denormalizedAssetInWalletBalance = denormalizeNumber(assetWalletBalance, BigInt(NATIVE_CURRENCY_PRECISION));
|
||||
}
|
||||
const assetContractBalance = await exchangeContract.getBalance(assetAddress, walletAddress);
|
||||
const denormalizedAssetInContractBalance = denormalizeNumber(assetContractBalance, BigInt(INTERNAL_PROTOCOL_PRECISION));
|
||||
const denormalizedAssetInContractBalance = denormalizeNumber(
|
||||
assetContractBalance,
|
||||
BigInt(INTERNAL_PROTOCOL_PRECISION)
|
||||
);
|
||||
const denormalizedAssetLockedBalanceResult = await aggregator.getLockedBalance(walletAddress, assetName);
|
||||
if (denormalizedAssetLockedBalanceResult.isErr()) {
|
||||
throw new Error(denormalizedAssetLockedBalanceResult.error.message);
|
||||
@@ -42,21 +47,130 @@ export default async function getBalance(
|
||||
};
|
||||
}
|
||||
|
||||
export async function getWalletBalance(
|
||||
assetAddress: string,
|
||||
walletAddress: string,
|
||||
async function getExchangeBalanceERC20(
|
||||
tokenAddress: AddressLike,
|
||||
walletAddress: AddressLike,
|
||||
exchangeAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToNativeDecimals = true
|
||||
) {
|
||||
const assetIsNativeCryptocurrency = assetAddress === ethers.ZeroAddress;
|
||||
walletAddress = await addressLikeToString(walletAddress);
|
||||
exchangeAddress = await addressLikeToString(exchangeAddress);
|
||||
tokenAddress = await addressLikeToString(tokenAddress);
|
||||
|
||||
let assetWalletBalance: bigint | undefined;
|
||||
const exchange = <Exchange>Exchange__factory.connect(exchangeAddress, provider)
|
||||
const exchangeBalance = await exchange.getBalance(tokenAddress, walletAddress);
|
||||
|
||||
if (!assetIsNativeCryptocurrency) {
|
||||
const assetContract = ERC20__factory.connect(assetAddress, provider);
|
||||
assetWalletBalance = await assetContract.balanceOf(walletAddress);
|
||||
} else {
|
||||
assetWalletBalance = await provider.getBalance(walletAddress);
|
||||
if (convertToNativeDecimals) {
|
||||
const tokenContract = ERC20__factory.connect(tokenAddress, provider);
|
||||
const decimals = await tokenContract.decimals();
|
||||
const convertedExchangeBalance = (exchangeBalance * BigInt(10) ** decimals) / BigInt(10) ** 8n;
|
||||
return convertedExchangeBalance;
|
||||
}
|
||||
|
||||
return assetWalletBalance
|
||||
return exchangeBalance;
|
||||
}
|
||||
|
||||
async function getExchangeBalanceNative(
|
||||
walletAddress: AddressLike,
|
||||
exchangeAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToNativeDecimals = true
|
||||
) {
|
||||
walletAddress = await addressLikeToString(walletAddress);
|
||||
exchangeAddress = await addressLikeToString(exchangeAddress);
|
||||
const exchange = <Exchange>Exchange__factory.connect(exchangeAddress, provider)
|
||||
const exchangeBalance = await exchange.getBalance(ZeroAddress, walletAddress);
|
||||
|
||||
if (convertToNativeDecimals) {
|
||||
const convertedExchangeBalance = (exchangeBalance * BigInt(10) ** 18n) / BigInt(10) ** 8n;
|
||||
return convertedExchangeBalance;
|
||||
}
|
||||
|
||||
return exchangeBalance;
|
||||
}
|
||||
|
||||
export async function getExchangeBalance(
|
||||
tokenAddress: AddressLike,
|
||||
walletAddress: AddressLike,
|
||||
exchangeAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToNativeDecimals = true
|
||||
) {
|
||||
walletAddress = await addressLikeToString(walletAddress);
|
||||
tokenAddress = await addressLikeToString(tokenAddress);
|
||||
|
||||
if (typeof tokenAddress === "string" && tokenAddress === ZeroAddress) {
|
||||
return getExchangeBalanceNative(walletAddress, exchangeAddress, provider, convertToNativeDecimals);
|
||||
} else {
|
||||
return getExchangeBalanceERC20(tokenAddress, walletAddress, exchangeAddress, provider, convertToNativeDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
async function getWalletBalanceERC20(
|
||||
tokenAddress: AddressLike,
|
||||
walletAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToExchangeDecimals = false
|
||||
) {
|
||||
walletAddress = await addressLikeToString(walletAddress);
|
||||
tokenAddress = await addressLikeToString(tokenAddress);
|
||||
|
||||
const tokenContract = ERC20__factory.connect(tokenAddress, provider);
|
||||
let walletBalance = await tokenContract.balanceOf(walletAddress);
|
||||
|
||||
if (convertToExchangeDecimals) {
|
||||
const tokenContract = ERC20__factory.connect(tokenAddress, provider);
|
||||
const decimals = await tokenContract.decimals();
|
||||
const convertedNativeBalance = (walletBalance * BigInt(10) ** 8n) / BigInt(10) ** decimals;
|
||||
return convertedNativeBalance;
|
||||
}
|
||||
return walletBalance;
|
||||
}
|
||||
|
||||
async function getWalletBalanceNative(
|
||||
walletAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToExchangeDecimals = false
|
||||
) {
|
||||
walletAddress = await addressLikeToString(walletAddress);
|
||||
const nativeBalance = await provider.getBalance(walletAddress);
|
||||
|
||||
if (convertToExchangeDecimals) {
|
||||
const convertedNativeBalance = (nativeBalance * BigInt(10) ** 8n) / BigInt(10) ** 18n;
|
||||
return convertedNativeBalance;
|
||||
}
|
||||
|
||||
return nativeBalance;
|
||||
}
|
||||
|
||||
export async function getWalletBalance(
|
||||
tokenAddress: AddressLike,
|
||||
walletAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToExchangeDecimals = false
|
||||
) {
|
||||
if (typeof tokenAddress === "string" && tokenAddress === ZeroAddress) {
|
||||
return getWalletBalanceNative(walletAddress, provider, convertToExchangeDecimals);
|
||||
} else {
|
||||
return getWalletBalanceERC20(tokenAddress, walletAddress, provider, convertToExchangeDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTotalBalance(
|
||||
tokenAddress: AddressLike,
|
||||
walletAddress: AddressLike,
|
||||
exchangeAddress: AddressLike,
|
||||
provider: ethers.Provider,
|
||||
convertToNativeDecimals = true
|
||||
) {
|
||||
const walletBalance = await getWalletBalance(tokenAddress, walletAddress, provider, !convertToNativeDecimals);
|
||||
const exchangeBalance = await getExchangeBalance(
|
||||
tokenAddress,
|
||||
walletAddress,
|
||||
exchangeAddress,
|
||||
provider,
|
||||
convertToNativeDecimals
|
||||
);
|
||||
return walletBalance + exchangeBalance;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user