Skip to content

Commit

Permalink
Merge pull request #440 from yieldprotocol/feat/hop-protocol-bridging
Browse files Browse the repository at this point in the history
integration: hop protocol bridging
  • Loading branch information
marcomariscal authored Sep 12, 2023
2 parents 95218df + 9b9347e commit ac265ef
Show file tree
Hide file tree
Showing 6 changed files with 5,288 additions and 1,937 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@center-inc/react": "^1.1.13",
"@headlessui/react": "^1.7.15",
"@heroicons/react": "^2.0.14",
"@hop-protocol/sdk": "^0.0.1-beta.535",
"@liquity/lib-base": "^3.0.0",
"@liquity/lib-ethers": "^3.4.0",
"@next/font": "13.1.2",
Expand Down
13 changes: 4 additions & 9 deletions src/components/cactiComponents/hooks/useSubmitTx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { TransactionReceipt } from '@ethersproject/abstract-provider';
import { useAddRecentTransaction } from '@rainbow-me/rainbowkit';
import {
CallOverrides,
Overrides,
PayableOverrides,
UnsignedTransaction,
} from 'ethers';
import { CallOverrides, Overrides, PayableOverrides, UnsignedTransaction } from 'ethers';
import {
usePrepareContractWrite,
usePrepareSendTransaction,
Expand Down Expand Up @@ -62,7 +57,7 @@ const useSubmitTx = (

/* prepare a send transaction if the fnName matches the SEND_TRANSACTION unique id */
const { config: sendConfig, isError: isPrepareError } = usePrepareSendTransaction({
request: { ...(writeConfig.request ?? sendParams), gasLimit: 500000 },
request: { ...(writeConfig.request ?? sendParams), gasLimit: sendParams?.gasLimit || 500000 },
enabled: true,
onError: (e) => console.log('prepare send error', e),
});
Expand All @@ -77,7 +72,7 @@ const useSubmitTx = (
isLoading: isPending,
isError,
isSuccess,
status
status,
} = useWaitForTransaction({
hash: data?.hash,
onSuccess: () => {
Expand Down Expand Up @@ -120,7 +115,7 @@ const useSubmitTx = (
isPending,
isSuccess,
error,
status
status,
};
};

Expand Down
10 changes: 10 additions & 0 deletions src/components/current/MessageTranslator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import WithdrawVault from './widgets/4626vault/WithdrawFromVault';
import DepositDSR from './widgets/dsr/DepositDSR';
import RedeemDSR from './widgets/dsr/RedeemDSR';
import StakeSfrxEth from './widgets/frax/StakeSfrxETH';
import HopBridge from './widgets/hop/HopBridge';
import LidoDeposit from './widgets/lido/LidoDeposit';
import LidoWithdraw from './widgets/lido/LidoWithdraw';
import LiquityBorrow from './widgets/liquity/borrow/LiquityBorrow';
Expand Down Expand Up @@ -312,6 +313,15 @@ export const Widget = (props: WidgetProps) => {
);
widgets.set('wrap-eth', <WrapEth amtString={'1'} />);
widgets.set('tx-replay', <TransactionReplay txHash={parsedArgs[0]} />);
widgets.set(
'hop-protocol-bridge',
<HopBridge
inputString={parsedArgs[0]}
tokenSymbol={parsedArgs[1]}
fromChain={parsedArgs[2]}
toChain={parsedArgs[3]}
/>
);

/* If available, return the widget in the widgets map */
if (widgets.has(fnName)) {
Expand Down
84 changes: 84 additions & 0 deletions src/components/current/widgets/hop/HopBridge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { useEffect, useState } from 'react';
import { Hop } from '@hop-protocol/sdk';
import { Interface, UnsignedTransaction } from 'ethers/lib/utils';
import { erc20ABI } from 'wagmi';
import { ActionResponse, HeaderResponse, SingleLineResponse } from '@/components/cactiComponents';
import { ApprovalBasicParams } from '@/components/cactiComponents/hooks/useApproval';
import useInput from '@/hooks/useInput';
import useSigner from '@/hooks/useSigner';
import useToken from '@/hooks/useToken';

interface HopBridgeProps {
inputString: string;
tokenSymbol: string;
fromChain: string;
toChain: string;
}

const HopBridge = ({ inputString, tokenSymbol, toChain, fromChain }: HopBridgeProps) => {
const _fromChain = fromChain === 'ethereum-mainnet' ? 'mainnet' : fromChain;

const signer = useSigner();
const { data: tokenIn } = useToken(tokenSymbol);
const input = useInput(inputString, tokenIn?.symbol!);
const [approvalParams, setApprovalParams] = useState<ApprovalBasicParams>();
const [sendParams, setSendParams] = useState<UnsignedTransaction>();
const [error, setError] = useState<string>();

useEffect(() => {
(async () => {
if (!input?.value) return console.error('No value to bridge');

try {
const hop = new Hop(_fromChain, signer);
const bridge = hop.bridge(tokenSymbol);

const needsApproval = await bridge.needsApproval(input.value, _fromChain);
if (needsApproval) {
// TODO wip

const { data } = await bridge.populateSendApprovalTx(input.value, _fromChain);

const erc20Interface = new Interface(erc20ABI);

const parsed = erc20Interface.parseTransaction({ data });
const spender = parsed.args[0];

setApprovalParams({
approvalAmount: input.value,
tokenAddress: tokenIn?.address!,
spender,
});
}

// TODO get the relevant to chain from hop
const req = await bridge.populateSendTx(input?.value, _fromChain, toChain);
setSendParams({ ...req, gasLimit: 10_000_000 }); // TODO figure out a better way to handle gas limits on forks
} catch (e) {
setError(e as string);
console.error('An error occurred:', e);
}
})();
}, [_fromChain, input?.value, toChain, tokenIn?.address, tokenSymbol]); // TODO signer is causing infinite loop

return (
<>
<HeaderResponse
text={`Bridge ${tokenSymbol} from ${_fromChain} to ${toChain} using Hop Protocol`}
/>
<SingleLineResponse tokenSymbol={tokenSymbol} value={input?.formatted} />
<ActionResponse
label={
error ??
`Bridge ${input?.formatted || ''} ${tokenSymbol} from ${_fromChain} to ${toChain}`
}
approvalParams={approvalParams}
txParams={undefined}
sendParams={sendParams}
disabled={!!error}
/>
</>
);
};

export default HopBridge;
20 changes: 13 additions & 7 deletions src/contexts/ChatContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ReactNode, createContext, useCallback, useContext, useEffect, useState } from 'react';
import { useQueryClient } from 'react-query';
import useWebSocket, { ReadyState } from 'react-use-websocket';
import { JsonValue } from 'react-use-websocket/dist/lib/types';
import { useRouter } from 'next/router';
import { useSession } from 'next-auth/react';
import { getBackendWebsocketUrl } from '@/utils/backend';
Expand All @@ -19,13 +18,20 @@ export type TruncateOptions = {
setBotThinking?: boolean;
};

type JSONPrimitive = string | number | boolean | null;
interface JSONObject {
[key: string]: JSONValue;
}
type JSONArray = JSONValue[];
export type JSONValue = JSONPrimitive | JSONObject | JSONArray;

export type ChatContextType = {
messages: Message[];
sendMessage: (msg: string) => void;
replayUserMessage: (msg: string) => void;
sendMultiStepClientMessage: (action: JsonValue) => void;
sendMultiStepClientMessage: (action: any) => void;
setIsMultiStepInProgress: (value: boolean) => void;
sendAction: (action: JsonValue) => void;
sendAction: (action: JSONValue) => void;
truncateUntilNextHumanMessage: (messageId: string, options?: TruncateOptions) => string | null;
spoofBotMessage: (msg: string) => void;
isBotThinking: boolean;
Expand All @@ -48,9 +54,9 @@ const initialContext = {
messages: [],
sendMessage: (msg: string) => {},
replayUserMessage: (msg: string) => {},
sendMultiStepClientMessage: (action: JsonValue) => {},
sendMultiStepClientMessage: (action: JSONValue) => {},
setIsMultiStepInProgress: (value: boolean) => {},
sendAction: (action: JsonValue) => {},
sendAction: (action: JSONValue) => {},
truncateUntilNextHumanMessage: (messageId: string, options?: TruncateOptions) => {
return null;
},
Expand Down Expand Up @@ -286,14 +292,14 @@ export const ChatContextProvider = ({ children }: { children: ReactNode }) => {
);

const sendMultiStepClientMessage = useCallback(
(payload: JsonValue) => {
(payload: JSONValue) => {
wsSendMessage({ actor: 'system', type: 'multistep-workflow', payload });
},
[wsSendMessage]
);

const sendAction = useCallback(
(action: JsonValue) => {
(action: JSONValue) => {
wsSendMessage({ actor: 'user', type: 'action', payload: action });
},
[wsSendMessage]
Expand Down
Loading

0 comments on commit ac265ef

Please sign in to comment.