Skip to content

Commit

Permalink
chore: IBC swap via interchain GPT added
Browse files Browse the repository at this point in the history
  • Loading branch information
deepan95dev committed Oct 17, 2024
1 parent 9d989ff commit 7135496
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 3 deletions.
5 changes: 5 additions & 0 deletions frontend/src/components/interchain-agent/ChatSuggestions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const SUGGESTIONS = [
text: 'send 1 ATOM to cosmos.... from chainID',
icon: '/sidebar-menu-icons/transfers-icon.svg',
},
{
title: 'IBC Swap',
text: 'swap 0.1 OSMO of osmosis to ATOM of cosmoshub',
icon: '/sidebar-menu-icons/transfers-icon.svg',
},
];

const ChatSuggestions = ({
Expand Down
28 changes: 28 additions & 0 deletions frontend/src/components/interchain-agent/InterchainAgentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ function parseTransaction(input: string): { type: string; data: any } | null {
const regexWithoutChainID =
/^(\w+)\s+(\d+(?:\.\d+)?)\s+(\w+)\s+to\s+([a-zA-Z0-9]+)$/i;

// Regex for "swap <amount> <denom> of <chainID> to <denom> of <chainID>"
const regexForIBCSwap =
/^(\w+)\s+(\d+(?:\.\d+)?)\s+(\w+)\s+of\s+([\w-]+)\s+to\s+(\w+)\s+of\s+([\w-]+)$/i;

let match;

// First, check for the regex with chainID
Expand Down Expand Up @@ -79,6 +83,30 @@ function parseTransaction(input: string): { type: string; data: any } | null {
};
}

match = input.match(regexForIBCSwap);
if(match){
const [
,
typeWithoutChainID,
amount,
sourceDenom,
sourceChainName,
destinationDenom,
destinationChainName
] = match;

return {
type: typeWithoutChainID,
data: {
amount: amount,
denom: sourceDenom.toLowerCase(),
sourceChainName: sourceChainName.toLowerCase(),
destinationDenom: destinationDenom.toLowerCase(),
destinationChainName: destinationChainName.toLowerCase(),
},
};
}

// If no pattern is matched, return null
return null;
}
Expand Down
107 changes: 105 additions & 2 deletions frontend/src/custom-hooks/interchain-agent/useTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ import {
txTransfer,
resetTxStatus as resetIBCTxStatus,
} from '@/store/features/ibc/ibcSlice';
import { txIBCSwap } from '@/store/features/swaps/swapsSlice';
import useAccount from '@/custom-hooks/useAccount';
import useChain from '@/custom-hooks/useChain';
import useSwaps from '@/custom-hooks/useSwaps';
import useGetChains from '@/custom-hooks/useGetChains';
// import useGetAssets from '@/custom-hooks/useGetAssets';

const SUPPORTED_TXNS = ['send', 'delegate'];
const SUPPORTED_TXNS = ['send', 'delegate', 'swap'];

const useTransactions = ({
userInput,
Expand All @@ -27,6 +33,19 @@ const useTransactions = ({
userInput: string;
chatInputTime: string;
}) => {
// Get Signer
const { getAccountAddress } = useAccount();

// To fetch 4 rest endpoints from chain-registry
const { getChainEndpoints, getExplorerEndpoints } = useChain();

const { getSwapRoute, routeError } = useSwaps();

const { chainsData } = useGetChains();

// const { getTokensByChainID, srcAssetsLoading, destAssetLoading } =
// useGetAssets();

const dispatch = useAppDispatch();
const {
getChainIDByCoinDenom,
Expand Down Expand Up @@ -90,7 +109,7 @@ const useTransactions = ({
return '';
};

const initiateTransaction = ({
const initiateTransaction = async ({
parsedData,
}: {
/* eslint-disable @typescript-eslint/no-explicit-any */
Expand Down Expand Up @@ -177,6 +196,90 @@ const useTransactions = ({
})
);
}
if (parsedData.type === 'swap') {
// IBC Swap via Interchain GPT bot
const selectedSourceChain: any = {};
const selectedDestChain: any = {};
const supportedChains = chainsData;
const sourceChain: any = supportedChains.find(
(chain: any) =>
chain.axelarChainName === parsedData.data.sourceChainName
);

// validate if source chain is supported
if (sourceChain) {
selectedSourceChain.chainID = sourceChain.chainId;
}

const destinationChain: any = supportedChains.find(
(chain: any) =>
chain.axelarChainName === parsedData.data.destinationChainName
);

// validate if destination chain is supported
if (destinationChain) {
selectedDestChain.chainID = destinationChain.chainId;
}

const { address: fromAddress } = await getAccountAddress(
sourceChain.chainId || ''
);
const { address: toAddress } = await getAccountAddress(
destinationChain.chainId || ''
);

const { rpcs, apis } = getChainEndpoints(
selectedSourceChain?.chainID || ''
);

const { explorerEndpoint } = getExplorerEndpoints(
selectedSourceChain?.chainID || ''
);
const { decimals } = getDenomInfo(selectedSourceChain.chainID);

const { route } = await getSwapRoute({
amount: Number(parsedData.data.amount) * 10 ** (decimals || 1),
destChainID: selectedDestChain?.chainID || '',
destDenom: `u${parsedData.data.destinationDenom}` || '',
sourceChainID: selectedSourceChain?.chainID || '',
sourceDenom: `u${parsedData.data?.denom}` || '',
fromAddress,
toAddress,
slippage: Number(0.5),
});
console.log("swap router error ", routeError);

if (routeError.length > 0) {
dispatch(
addSessionItem({
request: {
[userInput]: {
errMessage: '',
result: `Transaction failed: ${routeError}`,
status: 'failed',
date: chatInputTime,
},
},
sessionID: currentSessionID,
})
);
return;
}

if (route?.estimate) {
dispatch(
txIBCSwap({
rpcURLs: rpcs,
signerAddress: fromAddress,
sourceChainID: selectedSourceChain?.chainID || '',
destChainID: selectedDestChain?.chainID || '',
swapRoute: route,
explorerEndpoint,
baseURLs: apis,
})
);
}
}
};

useEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/custom-hooks/useGetChains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const useGetChains = () => {
chainsInfo,
getChainConfig,
getChainLogoURI,
chainsData
};
};

Expand Down
20 changes: 19 additions & 1 deletion frontend/src/store/features/swaps/swapsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
trackTransactionStatus,
txExecuteSwap,
} from './swapsService';
import { setError } from '../common/commonSlice';
import { setError, setGenericTxStatus } from '../common/commonSlice';
import { ERR_UNKNOWN } from '@/utils/errors';
import { OfflineDirectSigner } from '@cosmjs/proto-signing';
import { TxRaw } from 'cosmjs-types/cosmos/tx/v1beta1/tx';
Expand Down Expand Up @@ -103,20 +103,38 @@ export const txIBCSwap = createAsyncThunk(
status: 'success',
})
);
dispatch(
setGenericTxStatus({
status: TxStatus.IDLE,
errMsg: '',
})
);
} else if (txStatus === 'needs_gas') {
dispatch(
setError({
message: 'Transaction could not be completed, needs gas',
type: 'error',
})
);
dispatch(
setGenericTxStatus({
status: TxStatus.REJECTED,
errMsg: 'Transaction could not be completed, needs gas',
})
);
} else if (txStatus === 'partial_success') {
dispatch(
setTxDestSuccess({
msg: 'Transaction Partially Successful',
status: 'partial_success',
})
);
dispatch(
setGenericTxStatus({
status: TxStatus.REJECTED,
errMsg: 'Transaction Partially Successful',
})
);
} else if (txStatus === 'not_found') {
dispatch(
setError({
Expand Down

0 comments on commit 7135496

Please sign in to comment.