get past and new Transfer events for in/out txs

This commit is contained in:
Andrea Franz 2020-03-12 12:48:13 +01:00
parent c1ec94fa6c
commit affa0582a1
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
6 changed files with 94 additions and 58 deletions

View File

@ -3,7 +3,7 @@ import { RootState } from '../reducers';
import { Contract } from 'web3-eth-contract';
import Web3 from 'web3';
import { TransactionReceipt } from 'web3-core';
// import { loadBalance } from './wallet';
import { loadWalletBalance } from './wallet';
import { loadBlock } from './blocks';
import { abi as keycardWalletABI } from '../contracts/KeycardWallet';
import { addPadding } from "../utils";
@ -68,23 +68,6 @@ export const transactionConfirmed = (transactionHash: string): TxsTransactionCon
transactionHash,
});
export const watchPendingTransaction = (web3: Web3, dispatch: Dispatch, walletAddress: string | undefined, wallet: Contract, transactionHash: string) => {
web3.eth.getTransactionReceipt(transactionHash).then((tx: TransactionReceipt) => {
if (tx.status) {
dispatch(transactionConfirmed(transactionHash));
if (walletAddress !== undefined) {
// dispatch<any>(loadBalance(web3, walletAddress, wallet));
}
return;
}
window.setTimeout(() => watchPendingTransaction(web3, dispatch, walletAddress, wallet, transactionHash), 5000)
}).catch((error: string) => {
//FIXME: handle error
console.log("error", error)
});
}
export const loadTransactions = (web3: Web3, erc20: Contract) => {
return (dispatch: Dispatch, getState: () => RootState) => {
const state = getState();
@ -93,38 +76,87 @@ export const loadTransactions = (web3: Web3, erc20: Contract) => {
return;
}
const wallet = new web3.eth.Contract(keycardWalletABI, walletAddress);
const topic = web3.utils.sha3("Transfer(address,address,uint256)");
const options = {
fromBlock: 0,
toBlock: "latest",
topics: [
topic,
null,
addPadding(64, walletAddress),
]
};
erc20.getPastEvents("allEvents", options).then((events: any) => {
events.forEach((event: any) => {
const values = event.returnValues;
dispatch<any>(loadBlock(event.blockNumber));
dispatch(transactionDiscovered("TopUp", event.id, event.blockNumber, event.transactionHash, false, values.from, walletAddress, values.value));
});
dispatch(transactionsLoaded());
});
dispatch(loadingTransactions());
const filter = {
to: walletAddress,
};
web3.eth.getBlockNumber().then((blockNumber: number) => {
erc20.events.Transfer({filter: filter}).on('data', (event: any) => {
const values = event.returnValues;
dispatch(transactionDiscovered("TopUp", event.id, event.blockNumber, event.transactionHash, true, values.from, walletAddress, values.value));
watchPendingTransaction(web3, dispatch, walletAddress, wallet, event.transactionHash);
})
dispatch<any>(getPastTransactions(web3, erc20, walletAddress, blockNumber, "to"))
dispatch<any>(getPastTransactions(web3, erc20, walletAddress, blockNumber, "from"))
dispatch<any>(subscribeToTransactions(web3, erc20, walletAddress, blockNumber, "to"))
dispatch<any>(subscribeToTransactions(web3, erc20, walletAddress, blockNumber, "from"))
});
};
}
type ToOrFrom = "to" | "from";
const getPastTransactions = (web3: Web3, erc20: Contract, walletAddress: string, fromBlock: number, toOrFrom: ToOrFrom) => {
return (dispatch: Dispatch, getState: () => RootState) => {
const paddedWalletAddress = addPadding(64, walletAddress);
const eventType = toOrFrom == "to" ? "TopUp" : "NewPaymentRequest";
const topics: (null | string)[] = [null, null, null];
switch(toOrFrom) {
case "from":
topics[1] = paddedWalletAddress;
break;
case "to":
topics[2] = paddedWalletAddress;
break;
}
const options = {
fromBlock: 0,
toBlock: "latest",
topics: topics,
};
dispatch(loadingTransactions());
erc20.getPastEvents("Transfer", options).then((events: any) => {
events.forEach((event: any) => {
const values = event.returnValues;
dispatch<any>(loadBlock(event.blockNumber));
dispatch(transactionDiscovered(eventType, event.id, event.blockNumber, event.transactionHash, false, values.from, walletAddress, values.value));
});
dispatch(transactionsLoaded());
});
};
};
const subscribeToTransactions = (web3: Web3, erc20: Contract, walletAddress: string, fromBlock: number, toOrFrom: ToOrFrom) => {
return (dispatch: Dispatch, getState: () => RootState) => {
const options = {
fromBlock: fromBlock,
filter: {
[toOrFrom]: walletAddress,
}
};
const eventType = toOrFrom == "to" ? "TopUp" : "NewPaymentRequest";
erc20.events.Transfer(options).on('data', (event: any) => {
const values = event.returnValues;
const pending = event.blockHash === null;
dispatch(transactionDiscovered(eventType, event.id, event.blockNumber, event.transactionHash, pending, values.from, walletAddress, values.value));
dispatch<any>(loadWalletBalance(web3, undefined));
if (pending) {
watchPendingTransaction(web3, dispatch, walletAddress, event.transactionHash);
}
});
};
};
export const watchPendingTransaction = (web3: Web3, dispatch: Dispatch, walletAddress: string | undefined, transactionHash: string) => {
web3.eth.getTransactionReceipt(transactionHash).then((tx: TransactionReceipt) => {
if (tx.status) {
dispatch(transactionConfirmed(transactionHash));
if (walletAddress !== undefined) {
dispatch<any>(loadWalletBalance(web3, undefined));
}
return;
}
window.setTimeout(() => watchPendingTransaction(web3, dispatch, walletAddress, transactionHash), 5000)
}).catch((error: string) => {
//FIXME: handle error
console.log("error", error)
});
}

View File

@ -279,10 +279,14 @@ const loadERC20Symbol = (web3: Web3, erc20: Contract) => {
}
}
const loadWalletBalance = (web3: Web3, erc20: Contract) => {
export const loadWalletBalance = (web3: Web3, _erc20: Contract | undefined) => {
return async (dispatch: Dispatch, getState: () => RootState) => {
const address = getState().wallet.walletAddress!;
const state = getState();
const address = state.wallet.walletAddress!;
const erc20 = _erc20 !== undefined ? _erc20 : new web3.eth.Contract(erc20DetailedABI, state.wallet.erc20Address!);
dispatch(loadingWalletBalance(address));
return erc20.methods.balanceOf(address).call().then((balance: string) => {
dispatch(balanceLoaded(balance, balance));
return erc20;

View File

@ -12,7 +12,6 @@ export const VALID_NETWORK_ID = 3;
// export const VALID_NETWORK_ID = 5;
export const LOCAL_NETWORK_ID = 1337;
enum Web3Type {
Generic,
Remote,

View File

@ -39,7 +39,8 @@ const WalletsList = (props: Props) => {
{props.loading && <div className={classes.loading}>
<CircularProgress className={classes.progress} disableShrink></CircularProgress>
</div>}
{!props.loading && <List>
{<List>
{props.transactions.map((tx) => (
<TransactionsListItem key={tx.id} id={tx.id} />
))}

View File

@ -33,7 +33,7 @@ const mapStateToProps = (state: RootState): StateProps => {
return {
...props,
loading: state.transactions.loading,
loading: state.transactions.loadingRequests > 0,
transactions: transactions,
}
};

View File

@ -20,7 +20,7 @@ export interface TransactionState {
}
export interface TransactionsState {
loading: boolean
loadingRequests: number
transactions: {
[txHash: string]: TransactionState
}
@ -39,7 +39,7 @@ const newTransactionState = (): TransactionState => ({
});
const initialState: TransactionsState = {
loading: false,
loadingRequests: 0,
transactions: {},
};
@ -48,14 +48,14 @@ export const transactionsReducer = (state: TransactionsState = initialState, act
case TXS_LOADING: {
return {
...state,
loading: true,
loadingRequests: state.loadingRequests + 1,
}
}
case TXS_LOADED: {
return {
...state,
loading: false,
loadingRequests: state.loadingRequests - 1,
}
}