chore: add types

Not sure right now how to properly deal with `d.ts` files. So, I decided to let those types that depend on others inside a module.
This commit is contained in:
fernandomg 2020-05-27 08:47:44 -03:00
parent 1947f1c470
commit 6fb71d1ec4
9 changed files with 205 additions and 123 deletions

View File

@ -52,8 +52,26 @@ const METHOD_TO_ID = {
'0x694e80c3': SAFE_METHODS_NAMES.CHANGE_THRESHOLD,
}
export const decodeParamsFromSafeMethod = (data) => {
const [methodId, params] = [data.slice(0, 10), data.slice(10)]
type SafeMethods = typeof SAFE_METHODS_NAMES[keyof typeof SAFE_METHODS_NAMES]
type TokenMethods = 'transfer' | 'transferFrom' | 'safeTransferFrom'
type DecodedValues = Array<{
name: string
value: string
}>
type SafeDecodedParams = {
[key in SafeMethods]?: DecodedValues
}
type TokenDecodedParams = {
[key in TokenMethods]?: DecodedValues
}
export type DecodedMethods = SafeDecodedParams | TokenDecodedParams | null
export const decodeParamsFromSafeMethod = (data: string): SafeDecodedParams | null => {
const [methodId, params] = [data.slice(0, 10) as keyof typeof METHOD_TO_ID | string, data.slice(10)]
switch (methodId) {
// swapOwner
@ -104,11 +122,11 @@ export const decodeParamsFromSafeMethod = (data) => {
}
}
const isSafeMethod = (methodId: string) => {
const isSafeMethod = (methodId: string): boolean => {
return !!METHOD_TO_ID[methodId]
}
export const decodeMethods = (data: string) => {
export const decodeMethods = (data: string): DecodedMethods => {
const [methodId, params] = [data.slice(0, 10), data.slice(10)]
if (isSafeMethod(methodId)) {

View File

@ -1,6 +1,15 @@
import { Record } from 'immutable'
import { Record, RecordOf } from 'immutable'
export const makeToken = Record({
export type TokenProps = {
address: string
name: string
symbol: string
decimals: number | string
logoUri?: string | null
balance?: number | string
}
export const makeToken = Record<TokenProps>({
address: '',
name: '',
symbol: '',
@ -8,5 +17,6 @@ export const makeToken = Record({
logoUri: '',
balance: undefined,
})
// balance is only set in extendedSafeTokensSelector when we display user's token balances
export type Token = RecordOf<TokenProps>

View File

@ -1,15 +1,16 @@
import logo from 'src/assets/icons/icon_etherTokens.svg'
import generateBatchRequests from 'src/logic/contracts/generateBatchRequests'
import { getStandardTokenContract, getTokenInfos } from 'src/logic/tokens/store/actions/fetchTokens'
import { makeToken } from 'src/logic/tokens/store/model/token'
import { makeToken, Token } from 'src/logic/tokens/store/model/token'
import { ALTERNATIVE_TOKEN_ABI } from 'src/logic/tokens/utils/alternativeAbi'
import { web3ReadOnly as web3 } from 'src/logic/wallets/getWeb3'
import { isEmptyData } from 'src/routes/safe/store/actions/transactions/utils/transactionHelpers'
import { TxServiceModel } from 'src/routes/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions'
export const ETH_ADDRESS = '0x000'
export const SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH = '42842e0e'
export const getEthAsToken = (balance: string) => {
export const getEthAsToken = (balance: string): Token => {
return makeToken({
address: ETH_ADDRESS,
name: 'Ether',
@ -20,7 +21,7 @@ export const getEthAsToken = (balance: string) => {
})
}
export const isAddressAToken = async (tokenAddress) => {
export const isAddressAToken = async (tokenAddress): Promise<boolean> => {
// SECOND APPROACH:
// They both seem to work the same
// const tokenContract = await getStandardTokenContract()
@ -45,7 +46,9 @@ export const isSendERC721Transaction = (tx: any, txCode: string, knownTokens: an
)
}
export const getERC20DecimalsAndSymbol = async (tokenAddress: string): Promise<any> => {
export const getERC20DecimalsAndSymbol = async (
tokenAddress: string,
): Promise<{ decimals: number; symbol: string }> => {
const tokenInfos = await getTokenInfos(tokenAddress)
if (tokenInfos === null) {
@ -61,7 +64,11 @@ export const getERC20DecimalsAndSymbol = async (tokenAddress: string): Promise<a
return { decimals: Number(tokenInfos.decimals), symbol: tokenInfos.symbol }
}
export const isSendERC20Transaction = async (tx: any, txCode: string, knownTokens: any) => {
export const isSendERC20Transaction = async (
tx: TxServiceModel,
txCode: string,
knownTokens: any,
): Promise<boolean> => {
let isSendTokenTx = !isSendERC721Transaction(tx, txCode, knownTokens) && isTokenTransfer(tx)
if (isSendTokenTx) {

View File

@ -8,6 +8,7 @@ import FetchTransactions from 'src/routes/safe/store/actions/transactions/fetchT
import { buildTx, isCancelTransaction } from 'src/routes/safe/store/actions/transactions/utils/transactionHelpers'
import { SAFE_REDUCER_ID } from 'src/routes/safe/store/reducer/safe'
import { store } from 'src/store'
import { DecodedMethods } from 'src/logic/contracts/methodIds'
export type ConfirmationServiceModel = {
owner: string
@ -16,17 +17,13 @@ export type ConfirmationServiceModel = {
transactionHash: string
}
export type DecodedData = {
[key: string]: Array<{ [key: string]: string | number }>
}
export type TxServiceModel = {
baseGas: number
blockNumber?: number | null
confirmations: ConfirmationServiceModel[]
creationTx?: boolean | null
data?: string | null
dataDecoded?: DecodedData | null
dataDecoded?: DecodedMethods
executionDate?: string | null
executor: string
gasPrice: number

View File

@ -1,48 +1,57 @@
import { List, Map } from 'immutable'
import { decodeMethods } from 'src/logic/contracts/methodIds'
import { DecodedMethods, decodeMethods } from 'src/logic/contracts/methodIds'
import { TOKEN_REDUCER_ID } from 'src/logic/tokens/store/reducer/tokens'
import {
getERC20DecimalsAndSymbol,
isSendERC20Transaction,
isSendERC721Transaction,
} from 'src/logic/tokens/utils/tokenHelpers'
import { ZERO_ADDRESS, sameAddress } from 'src/logic/wallets/ethAddresses'
import { sameAddress, ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
import { makeConfirmation } from 'src/routes/safe/store/models/confirmation'
import { Confirmation } from 'src/routes/safe/store/models/types/confirmation'
import { makeTransaction } from 'src/routes/safe/store/models/transaction'
import {
Transaction,
TransactionStatus,
TransactionStatusValues,
TransactionTypes,
TransactionTypeValues,
} from 'src/routes/safe/store/models/types/transaction'
import { CANCELLATION_TRANSACTIONS_REDUCER_ID } from 'src/routes/safe/store/reducer/cancellationTransactions'
import { SAFE_REDUCER_ID } from 'src/routes/safe/store/reducer/safe'
import { TRANSACTIONS_REDUCER_ID } from 'src/routes/safe/store/reducer/transactions'
import { store } from 'src/store'
import { safeSelector, safeTransactionsSelector } from 'src/routes/safe/store/selectors'
import { addOrUpdateTransactions } from 'src/routes/safe/store/actions/transactions/addOrUpdateTransactions'
import { TxServiceModel } from 'src/routes/safe/store/actions/transactions/fetchTransactions/loadOutgoingTransactions'
export const isEmptyData = (data?: string | null) => {
export const isEmptyData = (data?: string | null): boolean => {
return !data || data === EMPTY_DATA
}
export const isInnerTransaction = (tx: any, safeAddress: string): boolean => {
export const isInnerTransaction = (tx: TxServiceModel, safeAddress: string): boolean => {
return sameAddress(tx.to, safeAddress) && Number(tx.value) === 0
}
export const isCancelTransaction = (tx: any, safeAddress: string): boolean => {
export const isCancelTransaction = (tx: TxServiceModel, safeAddress: string): boolean => {
return isInnerTransaction(tx, safeAddress) && isEmptyData(tx.data)
}
export const isPendingTransaction = (tx: any, cancelTx: any): boolean => {
export const isPendingTransaction = (tx: Transaction, cancelTx: Transaction): boolean => {
return (!!cancelTx && cancelTx.status === 'pending') || tx.status === 'pending'
}
export const isModifySettingsTransaction = (tx: any, safeAddress: string): boolean => {
export const isModifySettingsTransaction = (tx: TxServiceModel, safeAddress: string): boolean => {
return isInnerTransaction(tx, safeAddress) && !isEmptyData(tx.data)
}
export const isMultiSendTransaction = (tx: any): boolean => {
export const isMultiSendTransaction = (tx: TxServiceModel): boolean => {
return !isEmptyData(tx.data) && tx.data.substring(0, 10) === '0x8d80ff0a' && Number(tx.value) === 0
}
export const isUpgradeTransaction = (tx: any): boolean => {
export const isUpgradeTransaction = (tx: TxServiceModel): boolean => {
return (
!isEmptyData(tx.data) &&
isMultiSendTransaction(tx) &&
@ -51,11 +60,16 @@ export const isUpgradeTransaction = (tx: any): boolean => {
)
}
export const isOutgoingTransaction = (tx: any, safeAddress: string): boolean => {
export const isOutgoingTransaction = (tx: TxServiceModel, safeAddress: string): boolean => {
return !sameAddress(tx.to, safeAddress) && !isEmptyData(tx.data)
}
export const isCustomTransaction = async (tx: any, txCode: string, safeAddress: string, knownTokens: any) => {
export const isCustomTransaction = async (
tx: TxServiceModel,
txCode: string,
safeAddress: string,
knownTokens: any,
): Promise<boolean> => {
return (
isOutgoingTransaction(tx, safeAddress) &&
!(await isSendERC20Transaction(tx, txCode, knownTokens)) &&
@ -96,7 +110,7 @@ export const getRefundParams = async (
return refundParams
}
export const getDecodedParams = (tx: any): any => {
export const getDecodedParams = (tx: TxServiceModel): DecodedMethods => {
if (tx.dataDecoded) {
return Object.keys(tx.dataDecoded).reduce((acc, key) => {
acc[key] = {
@ -114,9 +128,9 @@ export const getDecodedParams = (tx: any): any => {
return null
}
export const getConfirmations = (tx: any): List<any> => {
export const getConfirmations = (tx: TxServiceModel): List<Confirmation> => {
return List(
tx.confirmations.map((conf: any) =>
tx.confirmations.map((conf) =>
makeConfirmation({
owner: conf.owner,
hash: conf.transactionHash,
@ -126,7 +140,11 @@ export const getConfirmations = (tx: any): List<any> => {
)
}
export const isTransactionCancelled = (tx: any, outgoingTxs: Array<any>, cancellationTxs: { number: any }): boolean => {
export const isTransactionCancelled = (
tx: TxServiceModel,
outgoingTxs: Array<TxServiceModel>,
cancellationTxs: { number: TxServiceModel },
): boolean => {
return (
// not executed
!tx.isExecuted &&
@ -137,49 +155,56 @@ export const isTransactionCancelled = (tx: any, outgoingTxs: Array<any>, cancell
)
}
export const calculateTransactionStatus = (tx: any, { owners, threshold }: any, currentUser?: string | null): any => {
export const calculateTransactionStatus = (
tx: Transaction,
{ owners, threshold }: any,
currentUser?: string | null,
): TransactionStatusValues => {
let txStatus
if (tx.isExecuted && tx.isSuccessful) {
txStatus = 'success'
txStatus = TransactionStatus.SUCCESS
} else if (tx.cancelled) {
txStatus = 'cancelled'
txStatus = TransactionStatus.CANCELLED
} else if (tx.confirmations.size === threshold) {
txStatus = 'awaiting_execution'
txStatus = TransactionStatus.AWAITING_EXECUTION
} else if (tx.creationTx) {
txStatus = 'success'
txStatus = TransactionStatus.SUCCESS
} else if (!tx.confirmations.size || !!tx.isPending) {
txStatus = 'pending'
txStatus = TransactionStatus.PENDING
} else {
const userConfirmed = tx.confirmations.filter((conf) => conf.owner === currentUser).size === 1
const userIsSafeOwner = owners.filter((owner) => owner.address === currentUser).size === 1
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
txStatus =
!userConfirmed && userIsSafeOwner
? TransactionStatus.AWAITING_YOUR_CONFIRMATION
: TransactionStatus.AWAITING_CONFIRMATIONS
}
if (tx.isSuccessful === false) {
txStatus = 'failed'
txStatus = TransactionStatus.FAILED
}
return txStatus
}
export const calculateTransactionType = (tx: any): string => {
let txType = 'outgoing'
export const calculateTransactionType = (tx: Transaction): TransactionTypeValues => {
let txType = TransactionTypes.OUTGOING
if (tx.isTokenTransfer) {
txType = 'token'
txType = TransactionTypes.TOKEN
} else if (tx.isCollectibleTransfer) {
txType = 'collectible'
txType = TransactionTypes.COLLECTIBLE
} else if (tx.modifySettingsTx) {
txType = 'settings'
txType = TransactionTypes.SETTINGS
} else if (tx.isCancellationTx) {
txType = 'cancellation'
txType = TransactionTypes.CANCELLATION
} else if (tx.customTx) {
txType = 'custom'
txType = TransactionTypes.CUSTOM
} else if (tx.creationTx) {
txType = 'creation'
txType = TransactionTypes.CREATION
} else if (tx.upgradeTx) {
txType = 'upgrade'
txType = TransactionTypes.UPGRADE
}
return txType
@ -193,7 +218,7 @@ export const buildTx = async ({
safe,
tx,
txCode,
}): Promise<any> => {
}): Promise<Transaction> => {
const safeAddress = safe.address
const isModifySettingsTx = isModifySettingsTransaction(tx, safeAddress)
const isTxCancelled = isTransactionCancelled(tx, outgoingTxs, cancellationTxs)
@ -208,7 +233,7 @@ export const buildTx = async ({
const confirmations = getConfirmations(tx)
const { decimals = null, symbol = null } = isSendERC20Tx ? await getERC20DecimalsAndSymbol(tx.to) : {}
const txToStore = makeTransaction({
const txToStore: Transaction = makeTransaction({
baseGas: tx.baseGas,
blockNumber: tx.blockNumber,
cancelled: isTxCancelled,
@ -252,7 +277,7 @@ export const buildTx = async ({
export const mockTransaction = (tx, safeAddress: string, state): Promise<any> => {
const submissionDate = new Date().toISOString()
const transactionStructure: any = {
const transactionStructure: TxServiceModel = {
blockNumber: null,
confirmationsRequired: null,
dataDecoded: decodeMethods(tx.data),
@ -290,9 +315,10 @@ export const mockTransaction = (tx, safeAddress: string, state): Promise<any> =>
})
}
export const updateStoredTransactionsStatus = (dispatch, walletRecord) => {
export const updateStoredTransactionsStatus = (dispatch, walletRecord): void => {
const state = store.getState()
const safe = safeSelector(state)
if (safe) {
const safeAddress = safe.address
const transactions = safeTransactionsSelector(state)

View File

@ -1,6 +1,7 @@
import { Record } from 'immutable'
import { ConfirmationProps } from './types/confirmation'
export const makeConfirmation = Record({
export const makeConfirmation = Record<ConfirmationProps>({
owner: '',
type: 'initialised',
hash: '',

View File

@ -1,70 +1,14 @@
import { List, Map, Record } from 'immutable'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import {
TransactionProps,
PendingActionType,
TransactionStatus,
TransactionTypes,
} from 'src/routes/safe/store/models/types/transaction'
export type TransactionType =
| 'incoming'
| 'outgoing'
| 'settings'
| 'custom'
| 'creation'
| 'cancellation'
| 'upgrade'
| 'token'
| 'collectible'
export type TransactionStatus =
| 'awaiting_your_confirmation'
| 'awaiting_confirmations'
| 'success'
| 'failed'
| 'cancelled'
| 'awaiting_execution'
| 'pending'
export type PendingActionType = 'Confirm' | 'Reject'
export type TransactionProps = {
baseGas: number
blockNumber?: number | null
cancelled?: boolean
confirmations: List<any>
creationTx: boolean
customTx: boolean
data?: string | null
decimals?: (number | string) | null
decodedParams: any
executionDate?: string | null
executionTxHash?: string | null
executor: string
gasPrice: number
gasToken: string
isCancellationTx: boolean
isCollectibleTransfer: boolean
isExecuted: boolean
isPending?: boolean
isSuccessful: boolean
isTokenTransfer: boolean
modifySettingsTx: boolean
multiSendTx: boolean
nonce?: number | null
operation: number
origin: string | null
ownersWithPendingActions: Map<PendingActionType, List<any>>
recipient: string
refundParams: any
refundReceiver: string
safeTxGas: number
safeTxHash: string
status?: TransactionStatus
submissionDate?: string | null
symbol?: string | null
type: TransactionType
upgradeTx: boolean
value: string
}
export const makeTransaction = Record({
export const makeTransaction = Record<TransactionProps>({
baseGas: 0,
blockNumber: 0,
cancelled: false,
@ -89,18 +33,16 @@ export const makeTransaction = Record({
nonce: 0,
operation: 0,
origin: null,
ownersWithPendingActions: Map({ confirm: List([]), reject: List([]) }),
ownersWithPendingActions: Map({ [PendingActionType.CONFIRM]: List([]), [PendingActionType.REJECT]: List([]) }),
recipient: '',
refundParams: null,
refundReceiver: ZERO_ADDRESS,
safeTxGas: 0,
safeTxHash: '',
status: 'awaiting',
status: TransactionStatus.PENDING,
submissionDate: '',
symbol: '',
type: 'outgoing',
type: TransactionTypes.OUTGOING,
upgradeTx: false,
value: 0,
value: '0',
})
export type Transaction = Record<TransactionProps>

View File

@ -0,0 +1,10 @@
import { RecordOf } from 'immutable'
export type ConfirmationProps = {
owner: string
type: string
hash: string
signature: string | null
}
export type Confirmation = RecordOf<ConfirmationProps>

View File

@ -0,0 +1,71 @@
export enum TransactionTypes {
INCOMING = 'incoming',
OUTGOING = 'outgoing',
SETTINGS = 'settings',
CUSTOM = 'custom',
CREATION = 'creation',
CANCELLATION = 'cancellation',
UPGRADE = 'upgrade',
TOKEN = 'token',
COLLECTIBLE = 'collectible',
}
export type TransactionTypeValues = typeof TransactionTypes[keyof typeof TransactionTypes]
export enum TransactionStatus {
AWAITING_YOUR_CONFIRMATION = 'awaiting_your_confirmation',
AWAITING_CONFIRMATIONS = 'awaiting_confirmations',
SUCCESS = 'success',
FAILED = 'failed',
CANCELLED = 'cancelled',
AWAITING_EXECUTION = 'awaiting_execution',
PENDING = 'pending',
}
export type TransactionStatusValues = typeof TransactionStatus[keyof typeof TransactionStatus]
export enum PendingActionType {
CONFIRM = 'confirm',
REJECT = 'reject',
}
export type PendingActionValues = PendingActionType[keyof PendingActionType]
export type TransactionProps = {
baseGas: number
blockNumber?: number | null
cancelled?: boolean
confirmations: import('immutable').List<any>
creationTx: boolean
customTx: boolean
data?: string | null
decimals?: (number | string) | null
decodedParams: import('src/logic/contracts/methodIds').DecodedMethods
executionDate?: string | null
executionTxHash?: string | null
executor: string
gasPrice: number
gasToken: string
isCancellationTx: boolean
isCollectibleTransfer: boolean
isExecuted: boolean
isPending?: boolean
isSuccessful: boolean
isTokenTransfer: boolean
modifySettingsTx: boolean
multiSendTx: boolean
nonce?: number | null
operation: number
origin: string | null
ownersWithPendingActions: import('immutable').Map<PendingActionValues, import('immutable').List<any>>
recipient: string
refundParams: any
refundReceiver: string
safeTxGas: number
safeTxHash: string
status?: TransactionStatus
submissionDate?: string | null
symbol?: string | null
type: TransactionTypes
upgradeTx: boolean
value: string
}
export type Transaction = import('immutable').RecordOf<TransactionProps>