Skip to content

Commit

Permalink
Merge pull request #284 from oraichain/feat/smart-router-osmosis-pool
Browse files Browse the repository at this point in the history
Feat/smart router osmosis pool
  • Loading branch information
haunv3 authored Jul 10, 2024
2 parents abc5487 + 40003a9 commit 5c71178
Show file tree
Hide file tree
Showing 11 changed files with 2,134 additions and 149 deletions.
2 changes: 1 addition & 1 deletion packages/oraidex-common/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@oraichain/oraidex-common",
"version": "1.0.88",
"version": "1.0.89",
"main": "build/index.js",
"files": [
"build/"
Expand Down
2 changes: 1 addition & 1 deletion packages/oraidex-common/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export const MULTICALL_CONTRACT = "orai1q7x644gmf7h8u8y6y8t9z9nnwl8djkmspypr6mxa
export const BASE_API_URL = "https://api.oraidex.io";

// alpha smart router
export const OSMOSIS_ROUTER_CONTRACT = "osmo1qxydza7ctzh9fn7sq5gcf0run8c78wh0jj47f4t5dwc5302r2dnqsp4hu6";
export const OSMOSIS_ROUTER_CONTRACT = "osmo1h3jkejkcpthl45xrrm5geed3eq75p5rgfce9taufkwfr89k63muqweu2y7";

// websocket consts
export const WEBSOCKET_RECONNECT_ATTEMPTS = 5;
Expand Down
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.0.89",
"version": "1.0.90",
"main": "build/index.js",
"files": [
"build/"
Expand Down
132 changes: 97 additions & 35 deletions packages/universal-swap/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ export class UniversalSwapHandler {
return receiver;
};

private getSwapAndActionInOsmosis(
public getSwapAndActionInOsmosis(
route: Routes,
{ oraiAddress, injAddress },
isOnlySwap: boolean,
Expand Down Expand Up @@ -420,7 +420,7 @@ export class UniversalSwapHandler {
return { msgTransferInfo };
}

private createForwardObject = (route: Routes, { oraiAddress, injAddress }) => {
public createForwardObject = (route: Routes, { oraiAddress, injAddress }) => {
const { prefixReceiver, chainInfoReceiver } = this.getPrefixCosmos(route);
return {
msgForwardObject: {
Expand Down Expand Up @@ -456,19 +456,17 @@ export class UniversalSwapHandler {
return { prefixRecover, prefixReceiver, chainInfoRecover, chainInfoReceiver };
};

private getMsgTransfer = (route: Routes, { oraiAddress, injAddress }) => {
public getMsgTransfer = (route: Routes, { oraiAddress, injAddress }, isLastRoute?: boolean) => {
const { prefixReceiver, prefixRecover, chainInfoRecover, chainInfoReceiver } = this.getPrefixCosmos(route);
const addressReceiver = this.getAddress(
prefixReceiver,
{ address60: injAddress, address118: oraiAddress },
chainInfoReceiver.bip44.coinType
);
return {
sourcePort: route.bridgeInfo.port,
sourceChannel: route.bridgeInfo.channel,
receiver: this.getReceiverIBCHooks(
route.tokenOutChainId,
this.getAddress(
prefixReceiver,
{ address60: injAddress, address118: oraiAddress },
chainInfoReceiver.bip44.coinType
)
),
receiver: isLastRoute ? addressReceiver : this.getReceiverIBCHooks(route.tokenOutChainId, addressReceiver),
token: {
amount: route.tokenInAmount,
denom: route.tokenIn
Expand All @@ -486,16 +484,21 @@ export class UniversalSwapHandler {
getMessagesAndMsgTransfers = (routeFlatten: Routes[], { oraiAddress, injAddress }) => {
let messages = [];
let msgTransfers = [];
let pathProperty = "";
let pathProperty = [];
let pathReceiver = [];

routeFlatten.forEach((route: Routes, index: number, routes: Routes[]) => {
const isLastRoute = index + 1 === routes.length;
const isLastRoute = route.isLastPath;

const isOsmosisChain = route.chainId === "osmosis-1";
const isSwap = route.type === "Swap";
const isConvert = route.type === "Convert";
const isBridge = route.type === "Bridge";

if (route.chainId === "Oraichain" && isSwap) {
if (route.chainId === "Oraichain" && !isBridge) {
// swap in oraichain
messages.push(...this.generateMsgsSmartRouterSwap(route));
if (isSwap) messages.push(...this.generateMsgsSmartRouterSwap(route, isLastRoute));
if (isConvert) messages.push(this.generateMsgsConvertSmartRouterSwap(route));
} else {
// initial msgTransfer
if (!msgTransfers[route.path]) {
Expand All @@ -508,30 +511,56 @@ export class UniversalSwapHandler {
true
);
msgTransfers[route.path] = msgActionSwap;
pathProperty = "msg.swap_and_action.post_swap_action";
pathProperty[route.path] = "msg.swap_and_action.post_swap_action";
pathReceiver[route.path] = isLastRoute
? pathProperty[route.path] + ".transfer.to_address"
: pathProperty[route.path] + ".ibc_transfer.ibc_info.receiver";
} else {
msgTransfers[route.path] = this.getMsgTransfer(route, { oraiAddress, injAddress });
pathProperty = "memo";
msgTransfers[route.path] = this.getMsgTransfer(route, { oraiAddress, injAddress }, isLastRoute);
pathProperty[route.path] = "memo";
pathReceiver[route.path] = "receiver";
}
} else {
if (isOsmosisChain) {
if (isSwap) {
const { msgActionSwap } = this.getSwapAndActionInOsmosis(route, { oraiAddress, injAddress }, isLastRoute);
this.updateNestedProperty(msgTransfers[route.path], pathProperty, msgActionSwap);
pathProperty += ".wasm.msg.swap_and_action.post_swap_action";
this.updateNestedProperty(msgTransfers[route.path], pathProperty[route.path], msgActionSwap);
pathProperty[route.path] += ".wasm.msg.swap_and_action.post_swap_action";
pathReceiver[route.path] = isLastRoute
? pathProperty[route.path] + ".transfer.to_address"
: pathProperty[route.path] + ".ibc_transfer.ibc_info.receiver";
} else if (index > 0 && routes[index - 1].chainId === route.chainId) {
const { msgTransferInfo } = this.getIbcTransferInfo(route, { oraiAddress, injAddress });
this.updateNestedProperty(msgTransfers[route.path], pathProperty, msgTransferInfo);
pathProperty += ".ibc_transfer.ibc_info.memo";
this.updateNestedProperty(msgTransfers[route.path], pathProperty[route.path], msgTransferInfo);
pathReceiver[route.path] = pathProperty[route.path] + ".ibc_transfer.ibc_info.receiver";
pathProperty[route.path] += ".ibc_transfer.ibc_info.memo";
}
} else {
const { msgForwardObject } = this.createForwardObject(route, { oraiAddress, injAddress });
this.updateNestedProperty(msgTransfers[route.path], pathProperty, msgForwardObject);
pathProperty += ".forward.next";
this.updateNestedProperty(msgTransfers[route.path], pathProperty[route.path], msgForwardObject);
pathReceiver[route.path] = pathProperty[route.path] + ".forward.receiver";
pathProperty[route.path] += ".forward.next";
}
}
}
});

const { recipientAddress, originalToToken } = this.swapData;
if (recipientAddress && msgTransfers?.length) {
for (let i = 0; i < msgTransfers.length; i++) {
const msg = msgTransfers[i];
const receiver = pathReceiver[i];

if (!receiver) continue;

const isValidRecipient = checkValidateAddressWithNetwork(recipientAddress, originalToToken.chainId);
if (!isValidRecipient.isValid) throw generateError("Recipient address invalid!");

this.updateNestedReceiveProperty(msg, receiver, recipientAddress);
}
}

msgTransfers = msgTransfers.filter(Boolean);
return { messages, msgTransfers };
};

Expand All @@ -550,7 +579,7 @@ export class UniversalSwapHandler {
}
);

const { routesFlatten } = this.flattenSmartRouters(alphaSmartRoutes.routes);
const routesFlatten = this.flattenSmartRouters(alphaSmartRoutes.routes);
const [oraiAddress, injAddress] = await Promise.all([
this.config.cosmosWallet.getKeplrAddr("Oraichain"),
this.config.cosmosWallet.getKeplrAddr("injective-1")
Expand All @@ -561,7 +590,6 @@ export class UniversalSwapHandler {
`There is a mismatch address between ${oraiAddress} and ${injAddress}. Should not using smart router swap!`
);
}

const { messages, msgTransfers } = await this.getMessagesAndMsgTransfers(routesFlatten, {
oraiAddress,
injAddress
Expand All @@ -586,17 +614,18 @@ export class UniversalSwapHandler {
return client.signAndBroadcast(this.swapData.sender.cosmos, [...msgExecuteSwap, ...transferStringifyMemo], "auto");
}

private flattenSmartRouters(routers: Route[]) {
flattenSmartRouters(routers: Route[]): Routes[] {
const routesFlatten = routers.flatMap((router, i) =>
router.paths.flatMap((path) =>
path.actions.map((action) => ({
router.paths.flatMap((path, ind, arrPath) =>
path.actions.map((action, index, arrAction) => ({
...action,
path: i,
chainId: path.chainId
chainId: path.chainId,
isLastPath: arrPath.length === ind + 1 && !arrAction[index + 1]
}))
)
);
return { routesFlatten };
return routesFlatten;
}

private updateNestedProperty = (obj, key, value) => {
Expand All @@ -607,6 +636,19 @@ export class UniversalSwapHandler {
}, obj)[keys[keys.length - 1]] = value;
};

private updateNestedReceiveProperty = (obj, path: string, value: any) => {
const keys = path.split(".");
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]]) {
throw new Error(`Invalid path: ${keys.slice(0, i + 1).join(".")}`);
}
current = current[keys[i]];
}
current[keys[keys.length - 1]] = value;
return obj;
};

private stringifyMemos = (obj) => {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
Expand Down Expand Up @@ -1034,7 +1076,7 @@ export class UniversalSwapHandler {
// version alpha smart router oraiDEX pool + osmosis pool
if (
swapOptions?.isAlphaSmartRouter &&
this.swapData?.alphaSmartRoutes?.routes.length &&
this.swapData?.alphaSmartRoutes?.routes?.length &&
["oraichain-to-oraichain", "oraichain-to-cosmos", "cosmos-to-others"].includes(universalSwapType)
) {
return this.alphaSmartRouterSwap();
Expand All @@ -1047,7 +1089,25 @@ export class UniversalSwapHandler {
return this.transferAndSwap(swapRoute);
}

generateMsgsSmartRouterSwap(route: Routes) {
generateMsgsConvertSmartRouterSwap(route: Routes) {
return {
contractAddress: route.tokenIn,
msg: {
send: {
contract: network.converter,
amount: route.tokenInAmount,
msg: toBinary({
convert_reverse: {
from: { native_token: { denom: route.tokenOut } }
}
})
}
},
funds: []
};
}

generateMsgsSmartRouterSwap(route: Routes, isLastRoute: boolean) {
let contractAddr: string = network.router;
const { originalFromToken, fromAmount } = this.swapData;
const fromTokenOnOrai = this.getTokenOnOraichain(originalFromToken.coinGeckoId);
Expand All @@ -1058,8 +1118,10 @@ export class UniversalSwapHandler {
"Could not calculate the minimum receive value because there is no simulate price or user slippage"
);
}
const to = this.swapData.recipientAddress;
const to = isLastRoute ? this.swapData.recipientAddress : undefined;
const { info: offerInfo } = parseTokenInfo(fromTokenOnOrai, _fromAmount);
const msgConvertsFrom = UniversalSwapHelper.generateConvertErc20Cw20Message(this.swapData.amounts, fromTokenOnOrai);

const routes = [route].map((route) => {
let ops = [];
let currTokenIn = offerInfo;
Expand All @@ -1080,7 +1142,7 @@ export class UniversalSwapHandler {
};
});
const msgs: ExecuteInstruction[] = this.buildSwapMsgsFromSmartRoute(routes, fromTokenOnOrai, to, contractAddr);
return msgs;
return buildMultipleExecuteMessages(msgs, ...msgConvertsFrom);
}

generateMsgsSwap() {
Expand Down
Loading

0 comments on commit 5c71178

Please sign in to comment.