Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/support swap oraidex osmosis #349

Merged
merged 11 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/universal-swap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@oraichain/oraidex-universal-swap",
"version": "1.1.14",
"version": "1.1.15",
"main": "build/index.js",
"files": [
"build/"
Expand Down
104 changes: 67 additions & 37 deletions packages/universal-swap/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import {
import { GasPrice } from "@cosmjs/stargate";
import { OraiswapRouterQueryClient } from "@oraichain/oraidex-contracts-sdk";
import { Affiliate } from "@oraichain/oraidex-contracts-sdk/build/OraiswapMixedRouter.types";
import { COSMOS_CHAIN_IDS } from "@oraichain/common";
import { COSMOS_CHAIN_IDS, EVM_CHAIN_IDS } from "@oraichain/common";
import { generateMsgSwap } from "./msg/msgs";

const AFFILIATE_DECIMAL = 1e4; // 10_000
Expand Down Expand Up @@ -277,7 +277,6 @@ export class UniversalSwapHandler {
let ibcInfos = ibcInfo;
let getEncodedExecuteMsgs = [];
if (["kawaii-islands", "milky-token"].includes(originalToToken.coinGeckoId)) {
const IBC_DECIMALS = 18;
const toTokenInOrai = this.getTokenOnOraichain(originalToToken.coinGeckoId, true);
const evmToken = tokenMap[toTokenInOrai.denom];
const evmAmount = coin(toAmount(this.swapData.fromAmount, evmToken.decimals).toString(), evmToken.denom);
Expand Down Expand Up @@ -1085,16 +1084,13 @@ export class UniversalSwapHandler {
);

// get swapRoute
const [oraiAddress, obridgeAddress] = await Promise.all([
this.config.cosmosWallet.getKeplrAddr("Oraichain"),
this.config.cosmosWallet.getKeplrAddr("oraibridge-subnet-2")
]);
const oraiAddress = await this.config.cosmosWallet.getKeplrAddr("Oraichain");

let minimumReceive = simulateAmount;
if (this.config.swapOptions?.isIbcWasm) minimumReceive = await this.caculateMinimumReceive();
if (this.config.swapOptions?.isIbcWasm) minimumReceive = await this.calculateMinimumReceive();

const { swapRoute: completeSwapRoute } = await UniversalSwapHelper.addOraiBridgeRoute(
{ obridgeAddress, sourceReceiver: oraiAddress, destReceiver: destinationReceiver },
{ sourceReceiver: oraiAddress, destReceiver: destinationReceiver },
originalFromToken,
originalToToken,
minimumReceive,
Expand Down Expand Up @@ -1174,55 +1170,89 @@ export class UniversalSwapHandler {
return this.transferAndSwap(swapRoute);
}

async processUniversalSwap() {
const { evm, tron } = this.swapData.sender;
const { originalFromToken, originalToToken, simulateAmount, recipientAddress, userSlippage, alphaSmartRoutes } =
this.swapData;
const { swapOptions } = this.config;
let toAddress = "";
const currentToNetwork = originalToToken.chainId;

async getToAddressUniversalSwap(evm, tron, recipientAddress, originalToToken) {
if (this.swapData.recipientAddress) {
const isValidRecipient = checkValidateAddressWithNetwork(recipientAddress, currentToNetwork);
const isValidRecipient = checkValidateAddressWithNetwork(recipientAddress, originalToToken.chainId);

if (!isValidRecipient.isValid) throw generateError("Recipient address invalid!");

toAddress =
originalToToken.chainId === ChainIdEnum.TRON
? tronToEthAddress(recipientAddress)
: this.swapData.recipientAddress;
return originalToToken.chainId === ChainIdEnum.TRON
? tronToEthAddress(recipientAddress)
: this.swapData.recipientAddress;
} else {
toAddress = await this.getUniversalSwapToAddress(originalToToken.chainId, {
return await this.getUniversalSwapToAddress(originalToToken.chainId, {
metamaskAddress: evm,
tronAddress: tron
});
}
}
haunv3 marked this conversation as resolved.
Show resolved Hide resolved

async processUniversalSwap() {
const { evm, tron } = this.swapData.sender;
const { originalFromToken, originalToToken, simulateAmount, recipientAddress, userSlippage, alphaSmartRoutes } =
this.swapData;
const { swapOptions } = this.config;

const toAddress = await this.getToAddressUniversalSwap(evm, tron, this.swapData.recipientAddress, originalToToken);
haunv3 marked this conversation as resolved.
Show resolved Hide resolved
const oraiAddress = await this.config.cosmosWallet.getKeplrAddr(COSMOS_CHAIN_IDS.ORAICHAIN);
if (!oraiAddress) throw generateError("orai address and obridge address invalid!");
const isValidRecipientOraichain = checkValidateAddressWithNetwork(oraiAddress, COSMOS_CHAIN_IDS.ORAICHAIN);
if (!isValidRecipientOraichain.isValid) throw generateError("orai get address invalid!");

let injAddress = undefined;
const [oraiAddress, obridgeAddress] = await Promise.all([
this.config.cosmosWallet.getKeplrAddr(COSMOS_CHAIN_IDS.ORAICHAIN),
this.config.cosmosWallet.getKeplrAddr(COSMOS_CHAIN_IDS.ORAIBRIDGE)
]);
let evmAddress = undefined;
let tronAddress = undefined;
let addressParams = {
oraiAddress,
injAddress,
evmInfo: {}
};

haunv3 marked this conversation as resolved.
Show resolved Hide resolved
let minimumReceive = simulateAmount;
if (swapOptions?.isIbcWasm) minimumReceive = await this.caculateMinimumReceive();

if (swapOptions?.isIbcWasm) minimumReceive = await this.calculateMinimumReceive();
haunv3 marked this conversation as resolved.
Show resolved Hide resolved
if (swapOptions?.isAlphaIbcWasm) {
const routesFlatten = UniversalSwapHelper.flattenSmartRouters(alphaSmartRoutes.routes);
const hasInjectiveAddress = routesFlatten.some((route) =>
[route.chainId, route.tokenOutChainId].includes(COSMOS_CHAIN_IDS.INJECTVE)
);
const [hasEVMChains, hasTron, hasInjectiveAddress] = [
routesFlatten.some((route) =>
[route.chainId, route.tokenOutChainId].some((id) =>
[EVM_CHAIN_IDS.ETH, EVM_CHAIN_IDS.BSC].includes(id as any)
)
),
routesFlatten.some((route) => [route.chainId, route.tokenOutChainId].includes(EVM_CHAIN_IDS.TRON)),
routesFlatten.some((route) => [route.chainId, route.tokenOutChainId].includes(COSMOS_CHAIN_IDS.INJECTVE))
];

if (hasInjectiveAddress) injAddress = await this.config.cosmosWallet.getKeplrAddr(COSMOS_CHAIN_IDS.INJECTVE);
if (hasInjectiveAddress) {
injAddress = await this.config.cosmosWallet.getKeplrAddr(COSMOS_CHAIN_IDS.INJECTVE);
addressParams.injAddress = injAddress;
}

if (hasEVMChains) {
evmAddress = this.swapData.sender.evm;
addressParams.evmInfo = {
...addressParams.evmInfo,
[EVM_CHAIN_IDS.ETH]: this.swapData.sender.evm,
[EVM_CHAIN_IDS.BSC]: this.swapData.sender.evm
};
}

if (hasTron) {
tronAddress = tronToEthAddress(this.swapData.sender.tron);
addressParams.evmInfo = {
...addressParams.evmInfo,
[EVM_CHAIN_IDS.TRON]: tronToEthAddress(this.swapData.sender.tron)
};
}
}

const { swapRoute, universalSwapType } = await UniversalSwapHelper.addOraiBridgeRoute(
{
obridgeAddress,
injAddress,
sourceReceiver: oraiAddress,
destReceiver: toAddress,
recipientAddress
recipientAddress,
evmAddress,
tronAddress
},
originalFromToken,
originalToToken,
Expand All @@ -1233,8 +1263,8 @@ export class UniversalSwapHandler {
);

if (alphaSmartRoutes?.routes?.length && swapOptions.isAlphaIbcWasm) {
let receiverAddresses = UniversalSwapHelper.generateAddress({ oraiAddress, injAddress });
if (recipientAddress) receiverAddresses[currentToNetwork] = toAddress;
let receiverAddresses = UniversalSwapHelper.generateAddress(addressParams);
if (recipientAddress) receiverAddresses[originalToToken.chainId] = toAddress;
return this.alphaSmartRouterSwapNewMsg(swapRoute, universalSwapType, receiverAddresses);
}

Expand All @@ -1253,7 +1283,7 @@ export class UniversalSwapHandler {
return this.transferAndSwap(swapRoute);
}

async caculateMinimumReceive() {
async calculateMinimumReceive() {
const { relayerFee, simulateAmount, originalToToken, bridgeFee = 1, userSlippage = 0 } = this.swapData;
const { cosmosWallet } = this.config;

Expand Down
96 changes: 74 additions & 22 deletions packages/universal-swap/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ import {
parseAssetInfoFromContractAddrOrDenom,
parseAssetInfo,
calculateTimeoutTimestamp,
COSMOS_CHAIN_ID_COMMON
COSMOS_CHAIN_ID_COMMON,
checkValidateAddressWithNetwork,
cosmosChains
} from "@oraichain/oraidex-common";
import {
ConvertReverse,
Expand Down Expand Up @@ -79,7 +81,7 @@ import { Amount, CwIcs20LatestQueryClient, Uint128 } from "@oraichain/common-con
import { CosmWasmClient, ExecuteInstruction, toBinary } from "@cosmjs/cosmwasm-stargate";
import { swapFromTokens, swapToTokens } from "./swap-filter";
import { Coin } from "@cosmjs/proto-signing";
import { AXIOS_TIMEOUT, IBC_TRANSFER_TIMEOUT } from "@oraichain/common";
import { AXIOS_TIMEOUT, COSMOS_CHAIN_IDS, EVM_CHAIN_IDS, IBC_TRANSFER_TIMEOUT } from "@oraichain/common";
import { TransferBackMsg } from "@oraichain/common-contracts-sdk/build/CwIcs20Latest.types";
import { buildUniversalSwapMemo } from "./proto/universal-swap-memo-proto-handler";
import { Affiliate } from "@oraichain/oraidex-contracts-sdk/build/OraiswapMixedRouter.types";
Expand Down Expand Up @@ -222,6 +224,9 @@ export class UniversalSwapHelper {
contractAddress?: string,
isSourceReceiverTest?: boolean
): string => {
const isValidRecipient = checkValidateAddressWithNetwork(oraiAddress, COSMOS_CHAIN_IDS.ORAICHAIN);
if (!isValidRecipient.isValid) throw generateError("orai Address get source receiver invalid!");

let sourceReceiver = `${oraib2oraichain}/${oraiAddress}`;
// TODO: test retire v2 (change structure memo evm -> oraichain)
if (isSourceReceiverTest) {
Expand Down Expand Up @@ -328,29 +333,58 @@ export class UniversalSwapHelper {
return toBech32(prefix, data);
};

static generateAddress = ({ oraiAddress, injAddress }) => {
/**
* need update when support new chain
*/
const addressFollowCoinType = { address60: injAddress, address118: oraiAddress };
return {
[COSMOS_CHAIN_ID_COMMON.INJECTVE_CHAIN_ID]: injAddress,
[COSMOS_CHAIN_ID_COMMON.ORAICHAIN_CHAIN_ID]: oraiAddress,
[COSMOS_CHAIN_ID_COMMON.ORAIBRIDGE_CHAIN_ID]: UniversalSwapHelper.getAddress("oraib", addressFollowCoinType),
[COSMOS_CHAIN_ID_COMMON.COSMOSHUB_CHAIN_ID]: UniversalSwapHelper.getAddress("cosmos", addressFollowCoinType),
[COSMOS_CHAIN_ID_COMMON.OSMOSIS_CHAIN_ID]: UniversalSwapHelper.getAddress("osmo", addressFollowCoinType),
[COSMOS_CHAIN_ID_COMMON.NOBLE_CHAIN_ID]: UniversalSwapHelper.getAddress("noble", addressFollowCoinType),
[COSMOS_CHAIN_ID_COMMON.CELESTIA_CHAIN_ID]: UniversalSwapHelper.getAddress("celestia", addressFollowCoinType)
static generateAddress = ({
oraiAddress,
injAddress,
evmInfo
}: {
oraiAddress: string;
injAddress?: string;
evmInfo?: {
[key: string]: string;
};
}) => {
const addressFollowCoinType = { address60: injAddress, address118: oraiAddress };
let cosmosAddress = cosmosChains.reduce(
(acc, cur) => {
if (!injAddress && cur?.bip44?.coinType === 60) return acc;
// coinType 118 cosmos
if (!acc?.[cur.chainId]) {
return {
...acc,
[cur.chainId]: UniversalSwapHelper.getAddress(
cur.bech32Config.bech32PrefixAccAddr,
addressFollowCoinType,
cur.bip44.coinType
)
};
}
return acc;
},
haunv3 marked this conversation as resolved.
Show resolved Hide resolved
{
Oraichain: oraiAddress,
[COSMOS_CHAIN_IDS.INJECTVE]: injAddress
}
);

if (evmInfo) {
cosmosAddress = {
...cosmosAddress,
...evmInfo
};
}

haunv3 marked this conversation as resolved.
Show resolved Hide resolved
return cosmosAddress;
};

static addOraiBridgeRoute = async (
addresses: {
obridgeAddress?: string;
sourceReceiver: string;
injAddress?: string;
destReceiver?: string;
recipientAddress?: string;
evmAddress?: string;
tronAddress?: string;
},
fromToken: TokenItemType,
toToken: TokenItemType,
Expand Down Expand Up @@ -380,13 +414,17 @@ export class UniversalSwapHelper {

if (isSmartRouter && swapOption.isIbcWasm && !swapOption?.isAlphaIbcWasm) {
if (!alphaSmartRoute && fromToken.coinGeckoId !== toToken.coinGeckoId) throw generateError(`Missing router !`);
const obridgeAddress = UniversalSwapHelper.getAddress("oraib", {
address118: addresses.sourceReceiver,
address60: addresses.injAddress
});

swapRoute = await UniversalSwapHelper.getRouteV2(
{
minimumReceive,
recoveryAddr: addresses.sourceReceiver,
destReceiver: addresses.destReceiver,
remoteAddressObridge: addresses.obridgeAddress
remoteAddressObridge: obridgeAddress
},
{
...alphaSmartRoute,
Expand All @@ -399,20 +437,34 @@ export class UniversalSwapHelper {
}

/**
* useAlphaIbcWasm case: (evm -> oraichain -> osmosis -> inj/tia not using wasm)
* useAlphaIbcWasm case:
* evm -> oraichain -> osmosis -> inj/tia
* tia/inj -> osmosis -> oraichain -> evm
*/
if (swapOption.isAlphaIbcWasm && !fromToken.cosmosBased) {
if (swapOption.isAlphaIbcWasm) {
if (!alphaSmartRoute) throw generateError(`Missing router with alpha ibc wasm!`);
const routes = alphaSmartRoute.routes;
const alphaRoutes = routes[0];
let paths = alphaRoutes.paths;

if (alphaSmartRoute.routes.length > 1) throw generateError(`Missing router with alpha ibc wasm max length!`);
const fromTokenIsEvm = !fromToken.cosmosBased;
// if from is EVM only support one routes
if (fromTokenIsEvm && alphaSmartRoute.routes.length > 1) {
throw generateError(`Missing router with alpha ibc wasm max length!`);
}

const paths = alphaRoutes.paths.filter((_, index) => index > 0);
if (fromTokenIsEvm) {
paths = alphaRoutes.paths.filter((_, index) => index > 0);
}

let receiverAddresses = UniversalSwapHelper.generateAddress({
injAddress: addresses.injAddress,
oraiAddress: addresses.sourceReceiver
oraiAddress: addresses.sourceReceiver,
evmInfo: !toToken.cosmosBased
? {
[toToken.chainId]: toToken.chainId === EVM_CHAIN_IDS.TRON ? addresses.tronAddress : addresses.evmAddress
}
: {}
});

if (addresses?.recipientAddress) receiverAddresses[toToken.chainId] = addresses?.recipientAddress;
Expand Down
8 changes: 3 additions & 5 deletions packages/universal-swap/src/msg/chains/oraichain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,11 +499,9 @@ export class OraichainMsg extends ChainMsg {
msg: toUtf8(
JSON.stringify({
send: {
send: {
contract: this.ENTRY_POINT_CONTRACT,
amount: this.path.tokenInAmount,
msg: toBinary(msg)
}
contract: this.ENTRY_POINT_CONTRACT,
amount: this.path.tokenInAmount,
msg: toBinary(msg)
}
})
),
Expand Down
Loading
Loading