Skip to content

Commit

Permalink
Merge pull request #105 from alephium/prepare-relayer
Browse files Browse the repository at this point in the history
Prepare relayer
  • Loading branch information
Lbqds authored Nov 17, 2023
2 parents e9a6df0 + a727724 commit 6f49a7b
Show file tree
Hide file tree
Showing 25 changed files with 5,893 additions and 5,537 deletions.
7 changes: 4 additions & 3 deletions bridge_ui/src/components/Transfer/RedeemPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CHAIN_ID_ALEPHIUM, isEVMChain } from "@alephium/wormhole-sdk";
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
selectTransferIsRedeemedViaRelayer,
selectTransferRedeemTx,
selectTransferTargetChain,
} from "../../store/selectors";
Expand All @@ -29,13 +30,13 @@ export default function RedeemPreview({
const dispatch = useDispatch();
const targetChain = useSelector(selectTransferTargetChain);
const redeemTx = useSelector(selectTransferRedeemTx);
const isRedeemedViaRelayer = useSelector(selectTransferIsRedeemedViaRelayer);
const handleResetClick = useCallback(() => {
dispatch(reset());
}, [dispatch]);

const explainerString =
overrideExplainerString ||
"Success! The redeem transaction was submitted. The tokens will become available once the transaction confirms.";
const explainerString = overrideExplainerString ||
`Success! The redeem transaction was submitted${(isRedeemedViaRelayer ? ' automatically by the relayer' : '')}. The tokens will become available once the transaction confirms.`;

return (
<>
Expand Down
2 changes: 1 addition & 1 deletion bridge_ui/src/components/Transfer/Target.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function Target() {
setAssociatedAccountExists={setAssociatedAccountExists}
/>
) : null}
{isEVMChain(targetChain) && !isReady ? null : <FeeMethodSelector />}
{((isEVMChain(targetChain) && !isReady) || (targetChain === CHAIN_ID_ALEPHIUM)) ? null : <FeeMethodSelector />}
<LowBalanceWarning chainId={targetChain} />
{targetChain === CHAIN_ID_SOLANA && CLUSTER === "mainnet" && (
<SolanaTPSWarning />
Expand Down
22 changes: 13 additions & 9 deletions bridge_ui/src/components/Transfer/WaitingForWalletMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useSelector } from "react-redux";
import {
selectTransferIsApproving,
selectTransferIsRedeeming,
selectTransferIsRedeemingViaRelayer,
selectTransferIsSending,
selectTransferIsWalletApproved,
selectTransferRedeemTx,
Expand Down Expand Up @@ -33,15 +34,18 @@ export default function WaitingForWalletMessage() {
const transferTx = useSelector(selectTransferTransferTx);
const targetChain = useSelector(selectTransferTargetChain);
const isRedeeming = useSelector(selectTransferIsRedeeming);
const isRedeemingViaRelayer = useSelector(selectTransferIsRedeemingViaRelayer);
const redeemTx = useSelector(selectTransferRedeemTx);
const showWarning =
const showNote =
isApproving || (isSending && !transferTx) || (isRedeeming && !redeemTx);
return showWarning ? (
<Typography className={classes.message} variant="body2">
{isWalletApproved ? WAITING_FOR_TX_CONFIRMATION : WAITING_FOR_WALLET_APPROVAL}{" "}
{targetChain === CHAIN_ID_SOLANA && isRedeeming
? "Note: there will be several transactions"
: null}
</Typography>
) : null;
return isRedeemingViaRelayer
? (<Typography className={classes.message} variant="body2">Trying to redeem via relayer...</Typography>)
: showNote
? (<Typography className={classes.message} variant="body2">
{isWalletApproved ? WAITING_FOR_TX_CONFIRMATION : WAITING_FOR_WALLET_APPROVAL}{" "}
{targetChain === CHAIN_ID_SOLANA && isRedeeming
? "Note: there will be several transactions"
: null}
</Typography>)
: null;
}
79 changes: 69 additions & 10 deletions bridge_ui/src/hooks/useHandleRedeem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
uint8ArrayToHex,
getTokenBridgeForChainId,
getIsTransferCompletedAlph,
redeemOnAlphWithReward
redeemOnAlphWithReward,
deserializeVAA
} from "@alephium/wormhole-sdk";
import { Alert } from "@material-ui/lab";
import { WalletContextState } from "@solana/wallet-adapter-react";
Expand All @@ -38,7 +39,7 @@ import {
selectTransferSourceChain,
selectTransferTargetChain,
} from "../store/selectors";
import { setIsRedeeming, setIsWalletApproved, setRedeemTx } from "../store/transferSlice";
import { setIsRedeemedViaRelayer, setIsRedeeming, setIsRedeemingViaRelayer, setIsWalletApproved, setRedeemCompleted, setRedeemTx } from "../store/transferSlice";
import { signSendAndConfirmAlgorand } from "../utils/algorand";
import {
ACALA_RELAY_URL,
Expand All @@ -54,6 +55,8 @@ import {
SOL_BRIDGE_ADDRESS,
SOL_TOKEN_BRIDGE_ADDRESS,
TERRA_TOKEN_BRIDGE_ADDRESS,
CLUSTER,
RELAYER_HOST,
} from "../utils/consts";
import parseError from "../utils/parseError";
import { postVaaWithRetry } from "../utils/postVaa";
Expand All @@ -63,6 +66,7 @@ import { getEmitterChainId, waitALPHTxConfirmed } from "../utils/alephium";
import useTransferSignedVAA from "./useTransferSignedVAA";
import { redeemOnEthNativeWithoutWait, redeemOnEthWithoutWait } from "../utils/ethereum";
import { useWallet, Wallet as AlephiumWallet } from "@alephium/web3-react";
import { SignerProvider } from "@alephium/web3";

async function algo(
dispatch: any,
Expand Down Expand Up @@ -235,6 +239,48 @@ async function terra(
}
}

async function redeemViaRelayer(
dispatch: any,
signer: SignerProvider,
tokenBridgeForChainId: string,
signedVAA: Uint8Array
): Promise<string | undefined> {
try {
dispatch(setIsRedeemingViaRelayer(true))
const parsedVAA = deserializeVAA(signedVAA)
const emitterChain = parsedVAA.body.emitterChainId.toString()
const targetChain = parsedVAA.body.targetChainId.toString()
const emitterAddress = uint8ArrayToHex(parsedVAA.body.emitterAddress)
const sequence = parsedVAA.body.sequence.toString()
const url = `${RELAYER_HOST}/vaas/${emitterChain}/${emitterAddress}/${targetChain}/${sequence}`
const { data } = await axios.request({ url, method: 'POST', timeout: 15000 })
if (data.error) {
throw new Error(data.error)
}
dispatch(setIsWalletApproved(true))
dispatch(setIsRedeemingViaRelayer(false))
dispatch(setIsRedeemedViaRelayer(true))
return data.txId ? data.txId as string : undefined
} catch (error) {
dispatch(setIsRedeemingViaRelayer(false))
console.error(`failed to redeem via relayer, error: ${error}`)
return await redeemManually(dispatch, signer, tokenBridgeForChainId, signedVAA)
}
}

async function redeemManually(
dispatch: any,
signer: SignerProvider,
tokenBridgeForChainId: string,
signedVAA: Uint8Array
): Promise<string> {
dispatch(setIsRedeemedViaRelayer(false))
const result = await redeemOnAlphWithReward(signer, ALEPHIUM_BRIDGE_REWARD_ROUTER_ID, tokenBridgeForChainId, signedVAA)
console.log(`the redemption tx has been submitted, txId: ${result.txId}`)
dispatch(setIsWalletApproved(true))
return result.txId
}

async function alephium(
dispatch: any,
enqueueSnackbar: any,
Expand All @@ -248,19 +294,31 @@ async function alephium(
try {
const emitterChainId = getEmitterChainId(signedVAA)
const tokenBridgeForChainId = getTokenBridgeForChainId(ALEPHIUM_TOKEN_BRIDGE_CONTRACT_ID, emitterChainId, ALEPHIUM_BRIDGE_GROUP_INDEX)
console.log('redeem on alephium')
const result = await redeemOnAlphWithReward(wallet.signer, ALEPHIUM_BRIDGE_REWARD_ROUTER_ID, tokenBridgeForChainId, signedVAA)
console.log(`the redeem tx has been submitted, txId: ${result.txId}`)
dispatch(setIsWalletApproved(true))
const confirmedTx = await waitALPHTxConfirmed(wallet.nodeProvider, result.txId, 1)

let txId: string | undefined = undefined
if (CLUSTER === 'mainnet') {
txId = await redeemViaRelayer(dispatch, wallet.signer, tokenBridgeForChainId, signedVAA)
} else {
txId = await redeemManually(dispatch, wallet.signer, tokenBridgeForChainId, signedVAA)
}

if (txId === undefined) {
dispatch(setRedeemCompleted())
enqueueSnackbar(null, {
content: <Alert severity="success">Transaction confirmed</Alert>,
});
return
}

const confirmedTx = await waitALPHTxConfirmed(wallet.nodeProvider, txId, 1)
const blockHeader = await wallet.nodeProvider.blockflow.getBlockflowHeadersBlockHash(confirmedTx.blockHash)
dispatch(
setRedeemTx({ id: result.txId, blockHeight: blockHeader.height })
setRedeemTx({ id: txId, blockHeight: blockHeader.height })
);
console.log(`the redeem tx has been confirmed, txId: ${result.txId}`)
console.log(`the redeem tx has been confirmed, txId: ${txId}`)
const isTransferCompleted = await getIsTransferCompletedAlph(
tokenBridgeForChainId,
wallet.account.group,
ALEPHIUM_BRIDGE_GROUP_INDEX,
signedVAA
)
if (isTransferCompleted) {
Expand All @@ -272,6 +330,7 @@ async function alephium(
content: <Alert severity="error">Transfer failed, please try again later</Alert>,
});
}

} catch (e) {
enqueueSnackbar(null, {
content: <Alert severity="error">{parseError(e)}</Alert>,
Expand Down
6 changes: 5 additions & 1 deletion bridge_ui/src/store/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ export const selectTransferIsWalletApproved = (state: RootState) =>
state.transfer.isWalletApproved
export const selectTransferIsRedeeming = (state: RootState) =>
state.transfer.isRedeeming;
export const selectTransferIsRedeemingViaRelayer = (state: RootState) =>
state.transfer.isRedeemingViaRelayer
export const selectTransferIsRedeemedViaRelayer = (state: RootState) =>
state.transfer.isRedeemedViaRelayer
export const selectTransferRedeemTx = (state: RootState) =>
state.transfer.redeemTx;
export const selectTransferIsApproving = (state: RootState) =>
Expand Down Expand Up @@ -352,7 +356,7 @@ export const selectTransferIsTargetComplete = (state: RootState) =>
export const selectTransferIsSendComplete = (state: RootState) =>
!!selectTransferSignedVAAHex(state);
export const selectTransferIsRedeemComplete = (state: RootState) =>
!!selectTransferRedeemTx(state);
!!selectTransferRedeemTx(state) || state.transfer.isRedeemCompleted;
export const selectTransferShouldLockFields = (state: RootState) =>
selectTransferIsSending(state) || selectTransferIsSendComplete(state);
export const selectTransferIsRecovery = (state: RootState) =>
Expand Down
23 changes: 23 additions & 0 deletions bridge_ui/src/store/transferSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ export interface TransferState {
isSending: boolean;
isWalletApproved: boolean;
isRedeeming: boolean;
isRedeemingViaRelayer: boolean;
isRedeemedViaRelayer: boolean;
redeemTx: Transaction | undefined;
isRedeemCompleted: boolean;
isApproving: boolean;
isRecovery: boolean;
gasPrice: number | undefined;
Expand All @@ -83,7 +86,10 @@ const initialState: TransferState = {
isSending: false,
isWalletApproved: false,
isRedeeming: false,
isRedeemingViaRelayer: false,
isRedeemedViaRelayer: false,
redeemTx: undefined,
isRedeemCompleted: false,
isApproving: false,
isRecovery: false,
gasPrice: undefined,
Expand Down Expand Up @@ -222,11 +228,24 @@ export const transferSlice = createSlice({
setIsRedeeming: (state, action: PayloadAction<boolean>) => {
state.isRedeeming = action.payload;
},
setIsRedeemingViaRelayer: (state, action: PayloadAction<boolean>) => {
state.isRedeemingViaRelayer = action.payload
},
setRedeemTx: (state, action: PayloadAction<Transaction>) => {
state.redeemTx = action.payload;
state.isRedeeming = false;
state.isRedeemingViaRelayer = false;
state.isWalletApproved = false;
},
setIsRedeemedViaRelayer: (state, action: PayloadAction<boolean>) => {
state.isRedeemedViaRelayer = action.payload
},
setRedeemCompleted: (state) => {
state.isRedeemCompleted = true
state.isRedeeming = false
state.isRedeemingViaRelayer = false;
state.isWalletApproved = false
},
setIsApproving: (state, action: PayloadAction<boolean>) => {
state.isApproving = action.payload;
},
Expand Down Expand Up @@ -270,6 +289,7 @@ export const transferSlice = createSlice({
state.activeStep = 3;
state.isRecovery = true;
state.redeemTx = undefined
state.isRedeemCompleted = false
state.useRelayer = action.payload.useRelayer;
},
setGasPrice: (state, action: PayloadAction<number | undefined>) => {
Expand Down Expand Up @@ -332,7 +352,10 @@ export const {
setIsSending,
setIsWalletApproved,
setIsRedeeming,
setIsRedeemingViaRelayer,
setRedeemTx,
setIsRedeemedViaRelayer,
setRedeemCompleted,
setIsApproving,
reset,
setRecoveryVaa,
Expand Down
7 changes: 7 additions & 0 deletions bridge_ui/src/utils/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,13 @@ export const EXPLORER_API_SERVER_HOST =
? 'https://v2.indexer-api.explorer.testnet.bridge.alephium.org'
: 'http://localhost:8100'

export const RELAYER_HOST =
CLUSTER === 'mainnet'
? 'https://relayer.bridge.alephium.org'
: CLUSTER === 'testnet'
? 'https://relayer.testnet.bridge.alephium.org'
: 'http://localhost:31000'

export const ALEPHIUM_HOST =
CLUSTER === "mainnet"
? alephiumMainnetConfig.nodeUrl
Expand Down
3 changes: 3 additions & 0 deletions build-docker-images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ docker build -f ./explorer-backend/Dockerfile . -t eu.gcr.io/alephium-org/wormho
### explorer
docker build -f ./explorer/Dockerfile . -t eu.gcr.io/alephium-org/wormhole-explorer:$version --build-arg network=$network

## relayer engine
docker build -f ./relayer-engine/Dockerfile . -t eu.gcr.io/alephium-org/relayer-engine:$version

if [ "${pushImage}" = true ]
then
docker push eu.gcr.io/alephium-org/guardiand:$version
Expand Down
4 changes: 4 additions & 0 deletions relayer-engine/.env.devnet
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ ETHEREUM_ADDRESSES=0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
BSC_ADDRESSES=0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
ALEPHIUM_ADDRESSES=1DrDyTr9RpRsQnDnXo2YRiPzPW4ooHX5LLoqXrqfMrpQH

ETHEREUM_NODE_URL=127.0.0.1:8545
BSC_NODE_URL=127.0.0.1:8546
ALEPHIUM_NODE_URL=http://127.0.0.1:22973

SPY_URL=localhost:7072
REDIS_URL=localhost:6379
14 changes: 14 additions & 0 deletions relayer-engine/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:16-buster-slim@sha256:93c9fc3550f5f7d159f282027228e90e3a7f8bf38544758024f005e82607f546

RUN mkdir /relayer-engine && mkdir /configs

COPY ./configs /configs
COPY ./relayer-engine/src /relayer-engine/src
COPY ./relayer-engine/package.json /relayer-engine/package.json
COPY ./relayer-engine/package-lock.json /relayer-engine/package-lock.json
COPY ./relayer-engine/tsconfig.json /relayer-engine/tsconfig.json

WORKDIR /relayer-engine

RUN --mount=type=cache,target=/home/node/.npm \
npm ci && npm run build
Loading

0 comments on commit 6f49a7b

Please sign in to comment.