From a25d648e14d7de0639cca38b4de58f09feda4093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sant=C3=A1ngelo?= Date: Fri, 21 May 2021 19:11:35 -0300 Subject: [PATCH 1/3] chore: wip --- src/modules/modal/actions.ts | 10 +-- src/modules/toast/actions.ts | 49 ++++++++++++ src/modules/toast/reducer.ts | 78 +++++++++++++++++++ src/modules/toast/selectors.ts | 16 ++++ src/modules/toast/types.ts | 5 ++ src/providers/ModalProvider/ModalProvider.tsx | 2 +- 6 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/modules/toast/actions.ts create mode 100644 src/modules/toast/reducer.ts create mode 100644 src/modules/toast/selectors.ts create mode 100644 src/modules/toast/types.ts diff --git a/src/modules/modal/actions.ts b/src/modules/modal/actions.ts index 67993e39..c2018cbd 100644 --- a/src/modules/modal/actions.ts +++ b/src/modules/modal/actions.ts @@ -1,11 +1,5 @@ import { action } from 'typesafe-actions' -export let modals: { [key: string]: any } = {} - -// Open Modal - -export const OPEN_MODAL = 'Open modal' - export const getModalActions = () => ({ openModal: function(name: T, metadata: any = null) { return action(OPEN_MODAL, { name, metadata }) @@ -20,6 +14,10 @@ export const getModalActions = () => ({ const { openModal, closeModal, toggleModal } = getModalActions() +// Open Modal + +export const OPEN_MODAL = 'Open modal' + export { openModal } export type OpenModalAction = ReturnType diff --git a/src/modules/toast/actions.ts b/src/modules/toast/actions.ts new file mode 100644 index 00000000..67993e39 --- /dev/null +++ b/src/modules/toast/actions.ts @@ -0,0 +1,49 @@ +import { action } from 'typesafe-actions' + +export let modals: { [key: string]: any } = {} + +// Open Modal + +export const OPEN_MODAL = 'Open modal' + +export const getModalActions = () => ({ + openModal: function(name: T, metadata: any = null) { + return action(OPEN_MODAL, { name, metadata }) + }, + closeModal: function(name: T) { + return action(CLOSE_MODAL, { name }) + }, + toggleModal: function(name: T) { + return action(TOGGLE_MODAL, { name }) + } +}) + +const { openModal, closeModal, toggleModal } = getModalActions() + +export { openModal } + +export type OpenModalAction = ReturnType + +// Close Modal + +export const CLOSE_MODAL = 'Close modal' + +export { closeModal } + +export type CloseModalAction = ReturnType + +// Toggle Modal + +export const TOGGLE_MODAL = 'Toggle modal' + +export { toggleModal } + +export type ToggleModalAction = ReturnType + +// Close All Modals + +export const CLOSE_ALL_MODALS = 'Close all modals' + +export const closeAllModals = () => action(CLOSE_ALL_MODALS, {}) + +export type CloseAllModalsAction = ReturnType diff --git a/src/modules/toast/reducer.ts b/src/modules/toast/reducer.ts new file mode 100644 index 00000000..06f77f4d --- /dev/null +++ b/src/modules/toast/reducer.ts @@ -0,0 +1,78 @@ +import { + OPEN_MODAL, + CLOSE_MODAL, + CLOSE_ALL_MODALS, + TOGGLE_MODAL, + OpenModalAction, + CloseModalAction, + CloseAllModalsAction, + ToggleModalAction +} from './actions' +import { Modal } from './types' + +export type ModalState = Record + +const INITIAL_STATE: ModalState = {} + +export type ModalReducerAction = + | OpenModalAction + | CloseModalAction + | CloseAllModalsAction + | ToggleModalAction + +export function modalReducer( + state = INITIAL_STATE, + action: ModalReducerAction +) { + switch (action.type) { + case OPEN_MODAL: { + const { name, metadata } = action.payload + + return { + ...state, + [name]: { + open: true, + name, + metadata + } + } + } + case CLOSE_MODAL: { + const { name } = action.payload + + if (state[name]) { + return { + ...state, + [name]: { + ...state[name], + open: false + } + } + } else { + // Invalid modal name + return state + } + } + case TOGGLE_MODAL: { + const { name } = action.payload + const modal = state[name] || { open: false } + + return { + ...state, + [name]: { + ...modal, + open: !modal.open + } + } + } + case CLOSE_ALL_MODALS: { + const newState = {} + for (const name in state) { + newState[name] = { ...state[name], open: false } + } + return newState + } + default: + return state + } +} diff --git a/src/modules/toast/selectors.ts b/src/modules/toast/selectors.ts new file mode 100644 index 00000000..66bbdae2 --- /dev/null +++ b/src/modules/toast/selectors.ts @@ -0,0 +1,16 @@ +import { ModalState } from './reducer' + +export const getState: (state: any) => ModalState = state => state.modal +export const getOpenModals: (state: any) => ModalState = state => { + const openModals = {} + const modals = getState(state) + + for (const name in modals) { + const modal = modals[name] + if (modal.open) { + openModals[name] = modal + } + } + + return openModals +} diff --git a/src/modules/toast/types.ts b/src/modules/toast/types.ts new file mode 100644 index 00000000..c5212354 --- /dev/null +++ b/src/modules/toast/types.ts @@ -0,0 +1,5 @@ +export type Modal = { + open: boolean + name: string + metadata: any +} diff --git a/src/providers/ModalProvider/ModalProvider.tsx b/src/providers/ModalProvider/ModalProvider.tsx index ee43f9a9..f5839c0a 100644 --- a/src/providers/ModalProvider/ModalProvider.tsx +++ b/src/providers/ModalProvider/ModalProvider.tsx @@ -7,7 +7,7 @@ export default class ModalProvider extends React.PureComponent { children: null } - getCloseHandler(name: string) { + getCloseHandler = (name: string) { return () => this.props.onClose(name) } From 7b074d0809f741d129115e8dc387def38649517a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sant=C3=A1ngelo?= Date: Thu, 27 May 2021 17:09:19 -0300 Subject: [PATCH 2/3] feat: lowercase addresses for all modules. export common middleware BREAKING CHANGE: will require local storage migrations --- src/modules/authorization/reducer.ts | 2 +- src/modules/common/middleware.ts | 73 +++++++++++++++++ src/modules/toast/actions.ts | 49 ------------ src/modules/toast/reducer.ts | 78 ------------------- src/modules/toast/selectors.ts | 16 ---- src/modules/toast/types.ts | 5 -- src/modules/transaction/actions.ts | 4 +- src/modules/transaction/reducer.ts | 74 ++++++------------ src/modules/wallet/selectors.ts | 2 +- src/providers/ModalProvider/ModalProvider.tsx | 2 +- 10 files changed, 102 insertions(+), 203 deletions(-) create mode 100644 src/modules/common/middleware.ts delete mode 100644 src/modules/toast/actions.ts delete mode 100644 src/modules/toast/reducer.ts delete mode 100644 src/modules/toast/selectors.ts delete mode 100644 src/modules/toast/types.ts diff --git a/src/modules/authorization/reducer.ts b/src/modules/authorization/reducer.ts index e805b707..bc9e30e3 100644 --- a/src/modules/authorization/reducer.ts +++ b/src/modules/authorization/reducer.ts @@ -38,7 +38,7 @@ const INITIAL_STATE = { error: null } -type AuthorizationReducerAction = +export type AuthorizationReducerAction = | FetchAuthorizationsRequestAction | FetchAuthorizationsSuccessAction | FetchAuthorizationsFailureAction diff --git a/src/modules/common/middleware.ts b/src/modules/common/middleware.ts new file mode 100644 index 00000000..8c051d9b --- /dev/null +++ b/src/modules/common/middleware.ts @@ -0,0 +1,73 @@ +import { RootMiddleware } from '../../types' +import { + FETCH_AUTHORIZATIONS_SUCCESS, + GRANT_TOKEN_SUCCESS, + REVOKE_TOKEN_SUCCESS +} from '../authorization/actions' +import { AuthorizationReducerAction } from '../authorization/reducer' +import { CHANGE_PROFILE, LOAD_PROFILE_SUCCESS } from '../profile/actions' +import { ProfileReducerAction } from '../profile/reducer' +import { + CLEAR_TRANSACTIONS, + FETCH_TRANSACTION_REQUEST, + FETCH_TRANSACTION_SUCCESS +} from '../transaction/actions' +import { TransactionReducerAction } from '../transaction/reducer' +import { + CHANGE_ACCOUNT, + CHANGE_NETWORK, + CONNECT_WALLET_SUCCESS, + FETCH_WALLET_SUCCESS +} from '../wallet/actions' +import { WalletReducerAction } from '../wallet/reducer' + +export const createCommonMiddleware = () => { + const middleware: RootMiddleware = () => next => ( + action: + | WalletReducerAction + | ProfileReducerAction + | TransactionReducerAction + | AuthorizationReducerAction + ) => { + switch (action.type) { + case FETCH_WALLET_SUCCESS: + case CONNECT_WALLET_SUCCESS: + case CHANGE_ACCOUNT: + case CHANGE_NETWORK: + action.payload.wallet.address = action.payload.wallet.address.toLowerCase() + break + case LOAD_PROFILE_SUCCESS: + case FETCH_TRANSACTION_REQUEST: + case CLEAR_TRANSACTIONS: + case CHANGE_PROFILE: + action.payload.address = action.payload.address.toLowerCase() + break + case FETCH_AUTHORIZATIONS_SUCCESS: + action.payload.authorizations = action.payload.authorizations.map( + authorization => ({ + ...authorization, + contractAddress: authorization.contractAddress.toLowerCase(), + authorizedAddress: authorization.authorizedAddress.toLowerCase() + }) + ) + break + case FETCH_TRANSACTION_SUCCESS: + const transaction = action.payload.transaction + + switch (transaction.actionType) { + case GRANT_TOKEN_SUCCESS: + case REVOKE_TOKEN_SUCCESS: { + const { authorization } = transaction.payload + authorization.contractAddress = authorization.contractAddress.toLowerCase() + authorization.authorizedAddress = authorization.authorizedAddress.toLowerCase() + break + } + } + break + } + + return next(action) + } + + return middleware +} diff --git a/src/modules/toast/actions.ts b/src/modules/toast/actions.ts deleted file mode 100644 index 67993e39..00000000 --- a/src/modules/toast/actions.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { action } from 'typesafe-actions' - -export let modals: { [key: string]: any } = {} - -// Open Modal - -export const OPEN_MODAL = 'Open modal' - -export const getModalActions = () => ({ - openModal: function(name: T, metadata: any = null) { - return action(OPEN_MODAL, { name, metadata }) - }, - closeModal: function(name: T) { - return action(CLOSE_MODAL, { name }) - }, - toggleModal: function(name: T) { - return action(TOGGLE_MODAL, { name }) - } -}) - -const { openModal, closeModal, toggleModal } = getModalActions() - -export { openModal } - -export type OpenModalAction = ReturnType - -// Close Modal - -export const CLOSE_MODAL = 'Close modal' - -export { closeModal } - -export type CloseModalAction = ReturnType - -// Toggle Modal - -export const TOGGLE_MODAL = 'Toggle modal' - -export { toggleModal } - -export type ToggleModalAction = ReturnType - -// Close All Modals - -export const CLOSE_ALL_MODALS = 'Close all modals' - -export const closeAllModals = () => action(CLOSE_ALL_MODALS, {}) - -export type CloseAllModalsAction = ReturnType diff --git a/src/modules/toast/reducer.ts b/src/modules/toast/reducer.ts deleted file mode 100644 index 06f77f4d..00000000 --- a/src/modules/toast/reducer.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { - OPEN_MODAL, - CLOSE_MODAL, - CLOSE_ALL_MODALS, - TOGGLE_MODAL, - OpenModalAction, - CloseModalAction, - CloseAllModalsAction, - ToggleModalAction -} from './actions' -import { Modal } from './types' - -export type ModalState = Record - -const INITIAL_STATE: ModalState = {} - -export type ModalReducerAction = - | OpenModalAction - | CloseModalAction - | CloseAllModalsAction - | ToggleModalAction - -export function modalReducer( - state = INITIAL_STATE, - action: ModalReducerAction -) { - switch (action.type) { - case OPEN_MODAL: { - const { name, metadata } = action.payload - - return { - ...state, - [name]: { - open: true, - name, - metadata - } - } - } - case CLOSE_MODAL: { - const { name } = action.payload - - if (state[name]) { - return { - ...state, - [name]: { - ...state[name], - open: false - } - } - } else { - // Invalid modal name - return state - } - } - case TOGGLE_MODAL: { - const { name } = action.payload - const modal = state[name] || { open: false } - - return { - ...state, - [name]: { - ...modal, - open: !modal.open - } - } - } - case CLOSE_ALL_MODALS: { - const newState = {} - for (const name in state) { - newState[name] = { ...state[name], open: false } - } - return newState - } - default: - return state - } -} diff --git a/src/modules/toast/selectors.ts b/src/modules/toast/selectors.ts deleted file mode 100644 index 66bbdae2..00000000 --- a/src/modules/toast/selectors.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ModalState } from './reducer' - -export const getState: (state: any) => ModalState = state => state.modal -export const getOpenModals: (state: any) => ModalState = state => { - const openModals = {} - const modals = getState(state) - - for (const name in modals) { - const modal = modals[name] - if (modal.open) { - openModals[name] = modal - } - } - - return openModals -} diff --git a/src/modules/toast/types.ts b/src/modules/toast/types.ts deleted file mode 100644 index c5212354..00000000 --- a/src/modules/toast/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type Modal = { - open: boolean - name: string - metadata: any -} diff --git a/src/modules/transaction/actions.ts b/src/modules/transaction/actions.ts index 1a247535..1deb6c00 100644 --- a/src/modules/transaction/actions.ts +++ b/src/modules/transaction/actions.ts @@ -125,8 +125,8 @@ export const replaceTransactionRequest = (hash: string, nonce: number) => nonce }) -export const replaceTransactionSuccess = (hash: string, replaceBy: string) => - action(REPLACE_TRANSACTION_SUCCESS, { hash, replaceBy }) +export const replaceTransactionSuccess = (hash: string, replacedBy: string) => + action(REPLACE_TRANSACTION_SUCCESS, { hash, replacedBy }) export const replaceTransactionFailure = (hash: string, error: string) => action(REPLACE_TRANSACTION_FAILURE, { diff --git a/src/modules/transaction/reducer.ts b/src/modules/transaction/reducer.ts index 1950c59d..b3fb9a67 100644 --- a/src/modules/transaction/reducer.ts +++ b/src/modules/transaction/reducer.ts @@ -51,7 +51,7 @@ export function transactionReducer( ): TransactionState { switch (action.type) { case FETCH_TRANSACTION_REQUEST: { - const actionRef = action.payload.action + const { address, action: actionRef } = action.payload const transaction = getTransactionFromAction(actionRef) const otherTransactions = state.data.filter( otherTransaction => otherTransaction.hash !== transaction.hash @@ -64,7 +64,7 @@ export function transactionReducer( { ...transaction, timestamp: Date.now(), - from: action.payload.address.toLowerCase(), + from: address, actionType: actionRef.type, // these always start as null, and they get updated by the saga status: null, @@ -75,18 +75,14 @@ export function transactionReducer( } } case FETCH_TRANSACTION_SUCCESS: { - const actionTransaction = action.payload.transaction + const { transaction } = action.payload return { loading: loadingReducer(state.loading, action), error: null, - data: state.data.map((transaction: Transaction) => - // prettier-ignore - actionTransaction.hash === transaction.hash - ? { - ...transaction, - ...actionTransaction - } - : transaction + data: state.data.map((stateTransaction: Transaction) => + transaction.hash === stateTransaction.hash + ? { ...stateTransaction, ...transaction } + : stateTransaction ) } } @@ -96,92 +92,70 @@ export function transactionReducer( loading: loadingReducer(state.loading, action), error: message, data: state.data.map((transaction: Transaction) => - // prettier-ignore - hash === transaction.hash - ? { - ...transaction, - status - } - : transaction + hash === transaction.hash ? { ...transaction, status } : transaction ) } } case UPDATE_TRANSACTION_STATUS: { + const { hash, status } = action.payload return { loading: loadingReducer(state.loading, action), error: null, data: state.data.map((transaction: Transaction) => - // prettier-ignore - action.payload.hash === transaction.hash - ? { - ...transaction, - status: action.payload.status - } - : transaction + hash === transaction.hash ? { ...transaction, status } : transaction ) } } case FIX_REVERTED_TRANSACTION: { + const { hash } = action.payload return { loading: loadingReducer(state.loading, action), error: null, data: state.data.map((transaction: Transaction) => - // prettier-ignore - action.payload.hash === transaction.hash - ? { - ...transaction, - status: TransactionStatus.CONFIRMED - } - : transaction + hash === transaction.hash + ? { ...transaction, status: TransactionStatus.CONFIRMED } + : transaction ) } } case UPDATE_TRANSACTION_NONCE: { + const { hash, nonce } = action.payload return { loading: loadingReducer(state.loading, action), error: null, data: state.data.map((transaction: Transaction) => - action.payload.hash === transaction.hash - ? { - ...transaction, - nonce: action.payload.nonce - } - : transaction + hash === transaction.hash ? { ...transaction, nonce } : transaction ) } } case REPLACE_TRANSACTION_SUCCESS: { + const { hash, replacedBy } = action.payload return { loading: loadingReducer(state.loading, action), error: null, data: state.data.map((transaction: Transaction) => - action.payload.hash === transaction.hash - ? { - ...transaction, - status: TransactionStatus.REPLACED, - replacedBy: action.payload.replaceBy - } + hash === transaction.hash + ? { ...transaction, status: TransactionStatus.REPLACED, replacedBy } : transaction ) } } case CLEAR_TRANSACTIONS: { + const { address, clearPendings } = action.payload return { ...state, data: state.data.filter( transaction => - transaction.from.toLowerCase() !== - action.payload.address.toLowerCase() && - (action.payload.clearPendings || !isPending(transaction.status)) + transaction.from.toLowerCase() !== address.toLowerCase() && + (clearPendings || !isPending(transaction.status)) ) } } case CLEAR_TRANSACTION: { + const { hash } = action.payload return { ...state, - data: state.data.filter( - transaction => transaction.hash !== action.payload.hash - ) + data: state.data.filter(transaction => transaction.hash !== hash) } } default: diff --git a/src/modules/wallet/selectors.ts b/src/modules/wallet/selectors.ts index 098d51a1..9ca17686 100644 --- a/src/modules/wallet/selectors.ts +++ b/src/modules/wallet/selectors.ts @@ -14,7 +14,7 @@ export const isEnabling = (state: any) => isLoadingType(getLoading(state), ENABLE_WALLET_REQUEST) export const getAddress = (state: any) => - isConnected(state) ? getData(state)!.address : undefined + isConnected(state) ? getData(state)!.address.toLowerCase() : undefined export const getChainId = (state: any) => isConnected(state) ? getData(state)!.chainId : undefined diff --git a/src/providers/ModalProvider/ModalProvider.tsx b/src/providers/ModalProvider/ModalProvider.tsx index f5839c0a..ee43f9a9 100644 --- a/src/providers/ModalProvider/ModalProvider.tsx +++ b/src/providers/ModalProvider/ModalProvider.tsx @@ -7,7 +7,7 @@ export default class ModalProvider extends React.PureComponent { children: null } - getCloseHandler = (name: string) { + getCloseHandler(name: string) { return () => this.props.onClose(name) } From b87cbda011587f3659252dda81d9e15709df5ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Sant=C3=A1ngelo?= Date: Thu, 27 May 2021 17:16:25 -0300 Subject: [PATCH 3/3] feat: compare addresses util --- src/modules/authorization/utils.ts | 7 ++++--- src/modules/transaction/sagas.ts | 5 +++-- src/modules/transaction/selectors.ts | 11 ++++++----- src/modules/wallet/utils.ts | 7 +++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/modules/authorization/utils.ts b/src/modules/authorization/utils.ts index ffc87c2f..ac2bd839 100644 --- a/src/modules/authorization/utils.ts +++ b/src/modules/authorization/utils.ts @@ -1,4 +1,5 @@ import { toBN } from 'web3x-es/utils' +import { isSameAddress } from '../wallet/utils' import { Authorization, AuthorizationType } from './types' export function getTokenAmountToApprove(): ReturnType { @@ -19,9 +20,9 @@ export function hasAuthorization( export function areEqual(left: Authorization, right: Authorization) { return ( left.type === right.type && - left.authorizedAddress === right.authorizedAddress && - left.contractAddress === right.contractAddress && - left.chainId === right.chainId + left.chainId === right.chainId && + isSameAddress(left.authorizedAddress, right.authorizedAddress) && + isSameAddress(left.contractAddress, right.contractAddress) ) } diff --git a/src/modules/transaction/sagas.ts b/src/modules/transaction/sagas.ts index 27b3ad56..37b6aacd 100644 --- a/src/modules/transaction/sagas.ts +++ b/src/modules/transaction/sagas.ts @@ -45,6 +45,7 @@ import { import { isPending, buildActionRef } from './utils' import { getTransaction as getTransactionFromChain } from './txUtils' import { getAddress } from '../wallet/selectors' +import { isSameAddress } from '../wallet/utils' import { getConnectedProvider } from '../../lib/eth' export function* transactionSaga(): IterableIterator { @@ -239,13 +240,13 @@ function* handleReplaceTransactionRequest( // look for a replacement tx, if so break the loop replacedBy = transactions.find( - tx => tx.nonce === nonce && tx.from.toString() === account + tx => tx.nonce === nonce && isSameAddress(tx.from, account) ) if (replacedBy) break // if no replacement is found, keep track of the highest nonce for the account highestNonce = transactions - .filter(tx => tx.from.toString() === account) + .filter(tx => isSameAddress(tx.from, account)) .reduce((max, tx) => Math.max(max, tx.nonce), highestNonce) } diff --git a/src/modules/transaction/selectors.ts b/src/modules/transaction/selectors.ts index 5a272bbd..162743e1 100644 --- a/src/modules/transaction/selectors.ts +++ b/src/modules/transaction/selectors.ts @@ -1,3 +1,4 @@ +import { isSameAddress } from '../wallet/utils' import { Transaction, TransactionStatus } from './types' import { TransactionState } from './reducer' import { isPending } from './utils' @@ -23,12 +24,12 @@ export const getTransactionsByStatus = ( status: TransactionStatus ): Transaction[] => getData(state) - .filter(tx => tx.from === address && tx.status === status) + .filter(tx => isSameAddress(tx.from, address) && tx.status === status) .sort(sortByTimestamp) export const getTransactions = (state: any, address: string): Transaction[] => getData(state) - .filter(tx => tx.from === address) + .filter(tx => isSameAddress(tx.from, address)) .sort(sortByTimestamp) export const getPendingTransactions = ( @@ -36,7 +37,7 @@ export const getPendingTransactions = ( address: string ): Transaction[] => getData(state) - .filter(tx => tx.from === address && isPending(tx.status)) + .filter(tx => isSameAddress(tx.from, address) && isPending(tx.status)) .sort(sortByTimestamp) export const getTransactionHistory = ( @@ -44,7 +45,7 @@ export const getTransactionHistory = ( address: string ): Transaction[] => getData(state) - .filter(tx => tx.from === address && !isPending(tx.status)) + .filter(tx => isSameAddress(tx.from, address) && !isPending(tx.status)) .sort(sortByTimestamp) export const getTransactionsByType = ( @@ -53,5 +54,5 @@ export const getTransactionsByType = ( type: string ): Transaction[] => getData(state) - .filter(tx => tx.from === address && tx.actionType === type) + .filter(tx => isSameAddress(tx.from, address) && tx.actionType === type) .sort(sortByTimestamp) diff --git a/src/modules/wallet/utils.ts b/src/modules/wallet/utils.ts index 58bf09f3..d8c34f07 100644 --- a/src/modules/wallet/utils.ts +++ b/src/modules/wallet/utils.ts @@ -71,3 +71,10 @@ export async function buildWallet(): Promise { chainId } } + +export function isSameAddress( + address1: Address | string, + address2: Address | string +) { + return address1.toString().toLowerCase() === address2.toString().toLowerCase() +}