Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: calc L2 tx hash in the background #169

Merged
merged 4 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ const TransactionSubmittedModal = ({transfer}) => {
});
}

if (
(type === ActionType.TRANSFER_TO_L1 && !isTransferCompleted) ||
type === ActionType.TRANSFER_TO_L2
) {
if (type === ActionType.TRANSFER_TO_L1 && !isTransferCompleted) {
explorerButtons.push({
explorerName: VOYAGER,
explorerUrl: voyagerTxUrl(l2hash),
Expand Down
22 changes: 7 additions & 15 deletions src/hooks/useTransferToL1.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,7 @@ export const useCompleteTransferToL1 = () => {
};

const onTransactionHash = (error, transactionHash) => {
if (error) {
onError(error);
} else {
if (!error) {
logger.log('Tx signed', {transactionHash});
handleProgress(
progressOptions.withdraw(
Expand All @@ -151,23 +149,14 @@ export const useCompleteTransferToL1 = () => {
};

const onWithdrawal = (error, event) => {
if (error) {
onError(error);
} else {
if (!error) {
logger.log('Withdrawal event dispatched', event);
const {transactionHash: l1hash} = event;
logger.log('Done', l1hash);
trackSuccess(l1hash);
handleData({...transfer, l1hash});
}
};

const onError = error => {
removeListener();
trackError(error);
logger.error(error?.message, error);
handleError(progressOptions.error(TransferError.TRANSACTION_ERROR, error));
};

try {
logger.log('CompleteTransferToL1 called');
handleProgress(
Expand All @@ -180,7 +169,10 @@ export const useCompleteTransferToL1 = () => {
logger.log('Calling withdraw');
await sendWithdrawal();
} catch (ex) {
onError(ex);
removeListener();
trackError(ex);
logger.error(ex?.message, ex);
handleError(progressOptions.error(TransferError.TRANSACTION_ERROR, ex));
}
},
[
Expand Down
78 changes: 21 additions & 57 deletions src/hooks/useTransferToL2.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@ import {useCallback} from 'react';

import {deposit, depositEth} from '../api/bridge';
import {allowance, approve, balanceOf, ethBalanceOf} from '../api/erc20';
import {
ActionType,
stepOf,
TransactionHashPrefix,
TransferError,
TransferStep,
TransferToL2Steps
} from '../enums';
import {ActionType, stepOf, TransferError, TransferStep, TransferToL2Steps} from '../enums';
import {starknet} from '../libs';
import {useDepositListener, useDepositMessageToL2Event} from '../providers/EventManagerProvider';
import {useDepositListener} from '../providers/EventManagerProvider';
import {useSelectedToken} from '../providers/TransferProvider';
import {useL1Wallet, useL2Wallet} from '../providers/WalletsProvider';
import utils from '../utils';
Expand All @@ -26,14 +19,13 @@ export const useTransferToL2 = () => {
const logger = useLogger('useTransferToL2');
const [trackInitiated, trackSuccess, trackError, trackReject] = useTransferToL2Tracking();
const {account: l1Account, chainId: l1ChainId, config: l1Config} = useL1Wallet();
const {account: l2Account, chainId: l2ChainId} = useL2Wallet();
const {account: l2Account} = useL2Wallet();
const {handleProgress, handleData, handleError} = useTransfer(TransferToL2Steps);
const selectedToken = useSelectedToken();
const getTokenContract = useTokenContract();
const getTokenBridgeContract = useTokenBridgeContract();
const progressOptions = useTransferProgress();
const {addListener, removeListener} = useDepositListener();
const getDepositMessageToL2Event = useDepositMessageToL2Event();
const maxTotalBalance = useMaxTotalBalance();

return useCallback(
Expand Down Expand Up @@ -81,9 +73,7 @@ export const useTransferToL2 = () => {
};

const onTransactionHash = (error, transactionHash) => {
if (error) {
onError(error);
} else {
if (!error) {
logger.log('Tx signed', {transactionHash});
handleProgress(
progressOptions.deposit(amount, symbol, stepOf(TransferStep.DEPOSIT, TransferToL2Steps))
Expand All @@ -92,43 +82,22 @@ export const useTransferToL2 = () => {
};

const onDeposit = async (error, event) => {
if (error) {
onError(error);
} else {
const l2MessageEvent = await getDepositMessageToL2Event(event);
if (l2MessageEvent) {
handleData({
type: ActionType.TRANSFER_TO_L2,
sender: l1Account,
recipient: l2Account,
name,
symbol,
amount,
...extractTransactionsHashFromEvent(l2MessageEvent)
});
}
if (!error) {
logger.log('Deposit event dispatched', event);
trackSuccess(event.transactionHash);
handleData({
type: ActionType.TRANSFER_TO_L2,
sender: l1Account,
recipient: l2Account,
l1hash: event.transactionHash,
name,
symbol,
amount,
event
});
}
};

const extractTransactionsHashFromEvent = event => {
const {to_address, from_address, selector, payload, nonce} = event.returnValues;
const l1hash = event.transactionHash;
const l2hash = utils.blockchain.starknet.getTransactionHash(
TransactionHashPrefix.L1_HANDLER,
from_address,
to_address,
selector,
payload,
l2ChainId,
nonce
);
trackSuccess({l1hash, l2hash});
return {
l1hash,
l2hash
};
};

const isMaxBalanceExceeded = async () => {
const tokenBridgeBalance = await (isEthToken
? ethBalanceOf(tokenBridgeAddress)
Expand All @@ -140,13 +109,6 @@ export const useTransferToL2 = () => {
return maxTotalBalance < tokenBridgeBalance + Number(amount);
};

const onError = error => {
removeListener();
trackError(error);
logger.error(error?.message, error);
handleError(progressOptions.error(TransferError.TRANSACTION_ERROR, error));
};

try {
logger.log('TransferToL2 called');
if (await isMaxBalanceExceeded()) {
Expand Down Expand Up @@ -177,15 +139,17 @@ export const useTransferToL2 = () => {
logger.log('Calling deposit');
await sendDeposit();
} catch (ex) {
onError(ex);
removeListener();
trackError(ex);
logger.error(ex?.message, ex);
handleError(progressOptions.error(TransferError.TRANSACTION_ERROR, ex));
}
},
[
selectedToken,
addListener,
removeListener,
l1ChainId,
l2ChainId,
l1Account,
l2Account,
l1Config,
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {App} from './App';
import {ModalWrapper} from './components/UI';
import envs from './config/envs';
import './index.scss';
import {Providers} from './providers';
import {AppProviders} from './providers';
import utils from './utils';

const {env} = envs;
Expand All @@ -24,10 +24,10 @@ if (env === 'development' || utils.browser.getUrlParameter('debugApp')) {

ReactDOM.render(
<BrowserRouter>
<Providers>
<AppProviders>
<App />
<ModalWrapper />
</Providers>
</AppProviders>
</BrowserRouter>,
document.getElementById('root')
);
18 changes: 11 additions & 7 deletions src/providers/EventManagerProvider/event-manager-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ export const useDepositMessageToL2Event = () => {
const {getPastEvents} = useContext(EventManagerContext);
const starknetContract = useStarknetContract();

return useCallback(async depositEvent => {
const {blockNumber, transactionHash} = depositEvent;
const pastEvents = await getPastEvents(starknetContract, EventName.L1.LOG_MESSAGE_TO_L2, {
fromBlock: blockNumber
});
return pastEvents.find(e => e.transactionHash === transactionHash);
}, []);
return useCallback(
async depositEvent => {
const {blockNumber, transactionHash} = depositEvent;
const pastEvents = await getPastEvents(starknetContract, EventName.L1.LOG_MESSAGE_TO_L2, {
fromBlock: blockNumber - 1,
toBlock: 'latest'
});
return pastEvents.find(e => e.transactionHash === transactionHash);
},
[starknetContract]
);
};
85 changes: 56 additions & 29 deletions src/providers/TransfersLogProvider/TransfersLogProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ import PropTypes from 'prop-types';
import React, {useEffect, useReducer} from 'react';
import useDeepCompareEffect from 'use-deep-compare-effect';

import {isCompleted, isConsumed} from '../../enums';
import {isCompleted, isConsumed, TransactionHashPrefix} from '../../enums';
import {useEnvs, useLogger} from '../../hooks';
import {starknet} from '../../libs';
import utils from '../../utils';
import {useBlockHash} from '../BlockHashProvider';
import {useDepositMessageToL2Event} from '../EventManagerProvider';
import {useTokens} from '../TokensProvider';
import {useL2Wallet} from '../WalletsProvider';
import {TransfersLogContext} from './transfers-log-context';
import {actions, initialState, reducer} from './transfers-log-reducer';

export const TransfersLogProvider = ({children}) => {
const [transfers, dispatch] = useReducer(reducer, initialState);
const {localStorageTransfersLogKey} = useEnvs();
const logger = useLogger(TransfersLogProvider.displayName);
const [transfers, dispatch] = useReducer(reducer, initialState);
const blockHash = useBlockHash();
const {updateTokenBalance} = useTokens();
const {chainId: l2ChainId} = useL2Wallet();
const getDepositMessageToL2Event = useDepositMessageToL2Event();

useEffect(() => {
const storedTransfers = getTransfersFromStorage();
Expand All @@ -30,35 +34,11 @@ export const TransfersLogProvider = ({children}) => {
if (!blockHash) {
return;
}
const checkTransaction = async transfer => {
if (isCompleted(transfer.status) || transfer.lastChecked === blockHash) {
return transfer;
}
try {
logger.log(`Checking tx status ${transfer.l2hash}`);
const {tx_status} = await starknet.defaultProvider.getTransactionStatus(transfer.l2hash);
if (transfer.status !== tx_status) {
logger.log(`Status changed from ${transfer.status}->${tx_status}`);
} else {
logger.log(`Status is still ${tx_status}`);
}
if (isConsumed(tx_status)) {
updateTokenBalance(transfer.symbol);
}
return {
...transfer,
status: tx_status,
lastChecked: blockHash
};
} catch (error) {
logger.error(`Failed to check transaction status: ${transfer.l2hash}`);
}
return transfer;
};

const newTransfers = [];
for (const transfer of transfers) {
const newTransfer = await checkTransaction(transfer);
const newTransfer = await (transfer.l2hash
? checkTransaction(transfer)
: calcL2TransactionHash(transfer));
newTransfers.push(newTransfer);
}
if (newTransfers.length) {
Expand All @@ -70,6 +50,53 @@ export const TransfersLogProvider = ({children}) => {
updateTransfers();
}, [blockHash, transfers]);

const checkTransaction = async transfer => {
if (isCompleted(transfer.status) || transfer.lastChecked === blockHash) {
return transfer;
}
try {
logger.log(`Checking tx status ${transfer.l2hash}`);
const {tx_status} = await starknet.defaultProvider.getTransactionStatus(transfer.l2hash);
if (transfer.status !== tx_status) {
logger.log(`Status changed from ${transfer.status}->${tx_status}`);
if (isConsumed(tx_status)) {
updateTokenBalance(transfer.symbol);
}
} else {
logger.log(`Status is still ${tx_status}`);
}
return {
...transfer,
status: tx_status,
lastChecked: blockHash
};
} catch (error) {
logger.error(`Failed to check transaction status: ${transfer.l2hash}`);
}
return transfer;
};

const calcL2TransactionHash = async transfer => {
const l2MessageEvent = await getDepositMessageToL2Event(transfer.event);
if (l2MessageEvent) {
const {to_address, from_address, selector, payload, nonce} = l2MessageEvent.returnValues;
delete transfer.event;
return {
...transfer,
l2hash: utils.blockchain.starknet.getTransactionHash(
TransactionHashPrefix.L1_HANDLER,
from_address,
to_address,
selector,
payload,
l2ChainId,
nonce
)
};
}
return transfer;
};

const updateTransfer = transfer => {
dispatch({
type: actions.UPDATE_TRANSFER,
Expand Down
2 changes: 1 addition & 1 deletion src/providers/WalletsProvider/WalletsProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import PropTypes from 'prop-types';
import React, {useEffect, useReducer} from 'react';
import {useWallet} from 'use-wallet';

import {WalletStatus} from '../../enums';
import {useIsL1, useIsL2} from '../TransferProvider';
import {WalletsContext} from './wallets-context';
import {useStarknetWallet} from './wallets-hooks';
import {actions, initialState, reducer} from './wallets-reducer';
import {WalletStatus} from '../../enums';

export const WalletsProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState);
Expand Down
Loading