Skip to content

Commit

Permalink
Merge pull request #19 from oraichain/feat/alloyed-token
Browse files Browse the repository at this point in the history
chore: support convert to alloy token
  • Loading branch information
trung2891 authored Sep 16, 2024
2 parents de90fb7 + 02f32c1 commit 20487ba
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 112 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

.env
2 changes: 1 addition & 1 deletion assets/icons/token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ export const OsmosisIcon = () => {
};

export const OraiIcon = () => {
const id = crypto.randomUUID();
const id = Math.random();
return (
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down
6 changes: 3 additions & 3 deletions assets/icons/wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ export const MetamaskIcon = () => {
};

export const KeplrIcon: FC<SVGProps<SVGSVGElement>> = (props) => {
const id = crypto.randomUUID();
const id = Math.random().toString();
return (
<svg
width="49"
Expand Down Expand Up @@ -457,7 +457,7 @@ export const TronLinkIcon = () => {
};

export const TonKeeperIcon = () => {
const id = crypto.randomUUID();
const id = Math.random();
return (
<svg
width="41"
Expand Down Expand Up @@ -499,7 +499,7 @@ export const TonKeeperIcon = () => {
};

export const MyTonWalletIcon = () => {
const id = crypto.randomUUID();
const id = Math.random();
return (
<svg
width="41"
Expand Down
2 changes: 1 addition & 1 deletion components/layout/connectedInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const CopyButton = ({ value }: { value: string }) => {

const handleCopy = (text) => {
navigator.clipboard
.writeText(text)
?.writeText(text)
.then(() => {
setIsCopied(true);
setCopiedValue(text);
Expand Down
20 changes: 19 additions & 1 deletion components/page/bridge/helper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
import { token } from "@oraichain/oraidex-common/build/typechain-types/@openzeppelin/contracts";
import {
AlloyedPool,
OsmosisAlloyedPools,
OsmosisTokenList,
} from "../../../constants/tokens";
import { fromBech32, toBech32 } from "@cosmjs/encoding";
import { Environment } from "@/constants/ton";

export const getAddressCosmos = (addr, prefix = "osmo") => {
if (!addr) throw "Address not found";
if (!addr) return undefined;
const { data } = fromBech32(addr);
const cosmosAddress = toBech32(prefix, data);
return cosmosAddress;
};

export const canConvertToAlloyedToken = (
coingeckoId: string
): AlloyedPool | undefined => {
const hasAlloyed = OsmosisTokenList(Environment.Mainnet).find(
(token) => token.coingeckoId == coingeckoId && token?.alloyedToken
);
return hasAlloyed
? OsmosisAlloyedPools.find((pool) => pool.alloyedToken == hasAlloyed.denom)
: undefined;
};
215 changes: 186 additions & 29 deletions components/page/bridge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
useAuthOraiAddress,
useAuthTonAddress,
} from "@/stores/authentication/selector";
import { toBinary } from "@cosmjs/cosmwasm-stargate";
import { ExecuteInstruction, toBinary } from "@cosmjs/cosmwasm-stargate";
import {
BigDecimal,
CW20_DECIMALS,
Expand All @@ -41,6 +41,8 @@ import {
CosmosChainId,
calculateTimeoutTimestamp,
getCosmosGasPrice,
OSMOSIS_ROUTER_CONTRACT,
getEncodedExecuteContractMsgs,
} from "@oraichain/oraidex-common";
import {
BridgeAdapter,
Expand Down Expand Up @@ -84,15 +86,17 @@ import { useCoinGeckoPrices } from "@/hooks/useCoingecko";
import SelectCommon from "@/components/commons/select";
import { NetworkWithIcon } from "@/constants/chainInfo";
import {
SwapAndAction,
UniversalSwapHelper,
buildUniversalSwapMemo,
} from "@oraichain/oraidex-universal-swap";
import { coin } from "@cosmjs/proto-signing";
import { Coin, coin, coins } from "@cosmjs/proto-signing";
import { getCosmWasmClient } from "@/libs/cosmjs";
import { GasPrice } from "@cosmjs/stargate";
import { getAddressCosmos } from "./helper";
import { canConvertToAlloyedToken, getAddressCosmos } from "./helper";
import { ArrowDownIcon } from "@/assets/icons/arrow";


const Bridge = () => {
const oraiAddress = useAuthOraiAddress();
const tonAddress = useAuthTonAddress();
Expand Down Expand Up @@ -304,6 +308,46 @@ const Bridge = () => {
}
};

const buildOsorSwapMsg = ({ user_swap, min_asset, timeout_timestamp, post_swap_action, affiliates }: SwapAndAction, isInitial: boolean, fromAddress?: string, funds?: Coin[]) => {
const msg = {
msg: {
swap_and_action: {
user_swap,
min_asset,
timeout_timestamp,
post_swap_action,
affiliates,
},
}
};

if (isInitial) {
if (!fromAddress) {
throw new Error("Missing fromAddress");
}
return {
msgActionSwap: {
sender: fromAddress,
contractAddress: OSMOSIS_ROUTER_CONTRACT,
funds,
...msg
}
};
}

return {
msgActionSwap: {
wasm: {
contract: OSMOSIS_ROUTER_CONTRACT,
...msg
}
}
};
};




const handleBridgeFromTon = async () => {
try {
if (!oraiAddress) throw "Please connect OWallet or Kelpr!";
Expand Down Expand Up @@ -348,11 +392,46 @@ const Bridge = () => {
: BRIDGE_TON_TO_ORAI_MINIMUM_GAS.toString();
const timeout = BigInt(Math.floor(new Date().getTime() / 1000) + 3600);


let memo = beginCell().endCell();

if (toNetwork.id === NetworkList["osmosis-1"].id) {
const osmosisAddress = await window.Keplr.getKeplrAddr(toNetwork.id);
let osmosisReceiver = osmosisAddress;
if (!osmosisAddress) throw "Please connect OWallet or Kelpr!";

let osorRouterMemo = "";
let hasAlloyedPool = canConvertToAlloyedToken(token.coingeckoId);
if (hasAlloyedPool) {
osmosisReceiver = OSMOSIS_ROUTER_CONTRACT;
let { msgActionSwap } = buildOsorSwapMsg({
user_swap: {
swap_exact_asset_in: {
swap_venue_name: "osmosis-poolmanager",
operations: [{
pool: hasAlloyedPool.poolId,
denom_in: hasAlloyedPool.sourceToken,
denom_out: hasAlloyedPool.alloyedToken
}]
}
},
min_asset: {
native: {
denom: hasAlloyedPool.alloyedToken,
amount: "0"
}
}, // consider add minimum receive (Currently, alloy pool is swap 1-1, so no't need to add min_asset
timeout_timestamp: Number(calculateTimeoutTimestamp(3600)),
post_swap_action: {
transfer: {
to_address: osmosisAddress,
},
},
affiliates: []
}, false);
osorRouterMemo = JSON.stringify(msgActionSwap);
}

const buildMemoSwap = buildUniversalSwapMemo(
{
minimumReceive: "0",
Expand All @@ -364,8 +443,8 @@ const Bridge = () => {
{
sourceChannel: "channel-13",
sourcePort: "transfer",
receiver: osmosisAddress,
memo: "",
receiver: osmosisReceiver,
memo: osorRouterMemo,
recoverAddress: oraiAddress,
},
undefined
Expand Down Expand Up @@ -489,6 +568,9 @@ const Bridge = () => {
isFromOraichainToOsmosis ||
isFromOsmosisToTon
) {
if (isFromOsmosisToTon && tonNetwork == "mainnet") {
validatePrice(token, amount);
}
const timeout = Math.floor(new Date().getTime() / 1000) + 3600;
const fromChainId = fromNetwork.id as CosmosChainId;
const toChainId = isFromOsmosisToTon
Expand Down Expand Up @@ -541,24 +623,99 @@ const Bridge = () => {
},
});
}
if (isFromOraichainToOsmosis) {
let hasAlloyedPool = canConvertToAlloyedToken(token.coingeckoId);
if (hasAlloyedPool) {
let { msgActionSwap } = buildOsorSwapMsg({
user_swap: {
swap_exact_asset_in: {
swap_venue_name: "osmosis-poolmanager",
operations: [{
pool: hasAlloyedPool.poolId,
denom_in: hasAlloyedPool.sourceToken,
denom_out: hasAlloyedPool.alloyedToken
}]
}
},
min_asset: {
native: {
denom: hasAlloyedPool.alloyedToken,
amount: "0"
}
}, // consider add minimum receive (Currently, alloy pool is swap 1-1, so no't need to add min_asset
timeout_timestamp: Number(calculateTimeoutTimestamp(3600)),
post_swap_action: {
transfer: {
to_address: toAddress,
},
},
affiliates: []
}, false);
memo = JSON.stringify(msgActionSwap);
toAddress = OSMOSIS_ROUTER_CONTRACT;
}
}

const ibcInfo = UniversalSwapHelper.getIbcInfo(fromChainId, toChainId);
const msgTransfer = [
{
typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
value: MsgTransfer.fromPartial({
sourcePort: ibcInfo.source,
sourceChannel: ibcInfo.channel,
token: coin(
toAmount(amount, token.decimal).toString(),
token.denom
),
sender: fromAddress,
receiver: toAddress,
memo,
timeoutTimestamp: calculateTimeoutTimestamp(ibcInfo.timeout),
}),
},
];
let executeMsg;
if (fromNetwork.id === NetworkList["osmosis-1"].id && token.alloyedToken) {
let hasAlloyedPool = canConvertToAlloyedToken(token.coingeckoId);
if (!hasAlloyedPool) throw new Error("AlloyPool does not exist!");
// need convert from alloyed first
let { msgActionSwap } = buildOsorSwapMsg({
user_swap: {
swap_exact_asset_in: {
swap_venue_name: "osmosis-poolmanager",
operations: [{
pool: hasAlloyedPool.poolId,
denom_in: hasAlloyedPool.alloyedToken,
denom_out: hasAlloyedPool.sourceToken
}]
}
},
min_asset: {
native: {
denom: hasAlloyedPool.sourceToken,
amount: "0"
}
}, // consider add minimum receive (Currently, alloy pool is swap 1-1, so no't need to add min_asset
timeout_timestamp: Number(calculateTimeoutTimestamp(3600)),
post_swap_action: {
ibc_transfer: {
ibc_info: {
source_channel: ibcInfo.channel,
receiver: toAddress,
memo,
recover_address: fromAddress
}
}
},
affiliates: []
}, true, fromAddress, coins(
toAmount(amount, token.decimal).toString(),
token.denom
));

executeMsg = getEncodedExecuteContractMsgs(fromAddress, [msgActionSwap as ExecuteInstruction])

} else
executeMsg = [
{
typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
value: MsgTransfer.fromPartial({
sourcePort: ibcInfo.source,
sourceChannel: ibcInfo.channel,
token: coin(
toAmount(amount, token.decimal).toString(),
token.denom
),
sender: fromAddress,
receiver: toAddress,
memo,
timeoutTimestamp: calculateTimeoutTimestamp(ibcInfo.timeout),
}),
},
];

const findCosmosChain = cosmosChains.find(
(chain) => chain.chainId === fromNetwork.id
Expand All @@ -576,7 +733,7 @@ const Bridge = () => {
);
const tx = await client.signAndBroadcast(
fromAddress,
msgTransfer,
executeMsg,
"auto"
);

Expand Down Expand Up @@ -979,10 +1136,10 @@ const Bridge = () => {
{/* <span className={styles.value}>1 TON</span> */}
<span className={styles.value}>
{toNetwork.id === NetworkList.ton.id ||
fromNetwork.id === NetworkList.ton.id
fromNetwork.id === NetworkList.ton.id
? numberWithCommas(bridgeFee || 0, undefined, {
maximumFractionDigits: CW20_DECIMALS,
})
maximumFractionDigits: CW20_DECIMALS,
})
: "0"}{" "}
{token?.symbol}
</span>
Expand All @@ -994,9 +1151,9 @@ const Bridge = () => {
{!token
? "--"
: formatDisplayNumber(
new BigDecimal(tokenFee).mul(amount || 0).toNumber(),
DECIMAL_TOKEN_FEE
)}{" "}
new BigDecimal(tokenFee).mul(amount || 0).toNumber(),
DECIMAL_TOKEN_FEE
)}{" "}
{token?.symbol}
</span>
</div>
Expand Down
Loading

0 comments on commit 20487ba

Please sign in to comment.