Development v2 fixes (#822)
* Bug: Invalid V in signature with eth_sign (#728) * Fix invalid V with metamask/ledger * DONT FORGET TO REVERT BEFORE MERGING: test deployment * DONT FORGET TO REVERT BEFORE MERGING 2: test deployment * Revert "DONT FORGET TO REVERT BEFORE MERGING 2: test deployment" This reverts commit 8331f2a78f7fc8f53eb893899f16edd8238c68ff. * Revert "DONT FORGET TO REVERT BEFORE MERGING: test deployment" This reverts commit 03b81e31820ce4fe078a7131c2f0caa2af4870ac. * BUG: Only injected providers are cached as last used provider (#733) * cache every used provider, not only injected one * package json update * (Fix) Adapt app to back-end changes (#736) * refactor: Set success status to `201` (CREATED) * refactor: return `null` when there's no latestTx * (Fix) Transaction not automatically executed (#716) * feature: action/reducer to UPDATE_SAFE_NONCE * refactor: when processing txs returned from backend, extract latest tx nonce value and store it in the safe's state * chore: update `yarn.lock` * refactor: `UPDATE_SAFE_THRESHOLD` and `UPDATE_SAFE_NONCE` discarded in favor of `UPDATE_SAFE` * refactor: use `SAFE_REDUCER_ID` constant * refactor: remove `updateSafeNonce` file * (Fix) Change the order of the upgrade methods lookup (#740) * fix: change the order of the upgrade methods lookup The `isUpgradeTransaction` method was looking for the methods in an wrong order (#599). The proper order was set in #610, but `isUpgradeTransaction` wasn't updated. * fix: contract upgrade version lookup * Feature: Use eth_sign for hardware wallets connected via onboard.js (#742) * Use eth_sign for hardware wallets * install onboard.js with fix from forked repo * rebuild yarn.lock to fix cached onboard * update bnc-onboard * update package json (#743) * (Fix) Properly decode threshold value in tx details (#749) * fix: Display new threshold value when changing its value There was a typo for the `changeThreshold` action fixes #746 * refactor: use a constant for safe methods names * fix: check for `decimals` method in transferredTokens (#748) Previously we were looking for `decimals` hash in the contract `code`. There are some contracts like USDC who happen to be behind a FiatTokenProxy, making it upgradable. By directly calling the `decimals()` method, we interact with the contract and can be sure that the `decimals()` method is present. fixes #678 * Bug #747: Don't use getLastTxNonce to fetch safe nonce (#750) * don't use getLastTxNonce to fetch safe nonce * fetch safe nonce in checkAndUpdateSafe * checkAndUpdateSafe refactor * remove nonce update logic from UPDATE_SAFE reducer * handle the case when localSafe returns undefined * handle the case when localSafe returns undefined in buildTransactionFrom * bump package json version to 1.9.4 * Issue-595: Apps config from Manifest (#715) * getting apps info from its manifest * Consume app info from manifest in Apps list, Transactions and Toast * fixes * navigate to TX Tab with an app makes a TX * (Fix) If backend returns `null` for addresses the Transaction ca… (#718) This tends to solve any possible issue that there may be in the tx execution for the `gasToken` and `refundReceiver` nullish values. fixes #573 * #751 fix - Replaces decimals from backend with decimals from blockchain (#755) * Replaces decimals from backend with decimals from blockchain * Removes fetching again token info from blockchain Fixs decimals cast, now we force to move from bignumber to number For data already wrong stored as string we remove it to force fetching again the decimals * Fixs missing symbol * Add description comment * Added Unilogin provider + support for legacy paths (#719) * Added unilogin provier + support for legacy path * Bump onboardjs version * fallback to displaying custom tx when we fail to fetch token info (#767) * Create release.yml Created script for building desktop app * Feature #322: Set safeTxGas for newly created transactions (#752) * Set safeTxGas for newly created transactions * extending estimation for nested calls WIP * messing up things to implement safeTxGas estimation * simplifying base gas calculations * remove eslint disable * messing things up to make things work * bring estimateData back * pass payload to requiredTxGas * pass esimateData to estimateDataGasCosts * remove console log * use batch requests to estimate safeTxGas * use const for txGasEstimation * check the response in request simultion * sidebar fix * remove for loop * Manage Apps (#765) * getting apps info from its manifest * Consume app info from manifest in Apps list, Transactions and Toast * fixes * navigate to TX Tab with an app makes a TX * ManageApps partial implementation * update safe-react-components * changes * apps validator * fix providedBy * TextField in addApp * fix checkbox error message * validation * adding app * Manage Apps * fix modal width * update package.json * update netlify url * fix modal widh * Set layout to Non-owners allowed error * some fixes * Apply suggestions from code review Co-Authored-By: lukasschor <lukas.schor@gnosis.pm> * review changes * fix condition * Legal Disclaimer * Better error message * update yarn.lock * Error message * review fixes * upgrade safe-react-components * show for all environments * Disclaimer changes * review changes * fix re-render * visual changes Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> Co-authored-by: lukasschor <lukas.schor@gnosis.pm> * fix scroll and fix margin layout * Add region to travis CI develop (#787) Enable region for s3 provider to allow upload development environment to different S3 regions * Feature/travis ci s3 region (#789) * Add region to travis CI develop Enable region for s3 provider to allow upload development environment to different S3 regions * Enable region for staging s3 providers * fix error on Wrapper * Add gnosis wc bridge to onboard.js wallets options array (#790) * Rename incoming-transactions url to incoming-transfers * Feature #587 - App performance improvement (#738) * Refactor Balances to functional component Removes Balances props in Layout.jsx * Replaces selectors that were using safeParamAddressSelector with safeParamAddressFromStateSelector to avoid the bug of non-loaded safe when called Also exports extendedTransactionsSelector to let the components use it * Refactors Transactions.jsx, replaces transactions.tsx with txsTable.jsx Removes all unused props from transactions.jsx Makes all childs of txsTable.jsx fetch the props they need instead of sharing all of them even if they are not used * Adds new selectors: safeNameSelector, safeNeedsUpdateSelector, safeCurrentVersionSelector * Removes unused props from layout to settings.jsx Removed props from the settings.jsx childs, now they fetch the values they need directly from the store * Removes unused redux connect * Adds safeEthBalanceSelector * Removes all the props from layout to settings * Refactor root and layout, extracts checkForUpdate and componentDidMount to components Extracts header and tabs from Layout.jsx * Makes routes.jsx use selectors instead of connect to unify the code * Loads tabs components using react suspense * Fixs warning when trying to update root component within loadStore.jsx Replaces safe with safeAddress selector in layout.jsx to reduce the unnecessary rendering Fixs setState in container.jsx * Fixs checkForUpdates fetchTokenBalances Adds FetchTokens.jsx in balances Adds safeFeaturesEnabledSelector * Fixs load addressbook action * Replaces safe with owners in manage owners * Improves buildSafe promises calls Improves the loadStorage calls * Fixs error "Uncaught (in promise) TypeError: Cannot read property 'includes' of undefined" * Extracts LoadStore from outside the router component to avoid re-loading the store Adds react lazy for Coins and Collectible tabs * Reduce the polling rate for fetching transactions * Removes unused actions.js Removes unused selector props * Fixes owners column selector usage * Fixes processTransaction usage * Optimize how the transaction list within the transactions tab are loaded * Fix lint error * Fix edit addressbook entry * Fixs show send coins modal * feature: batchRequest for incoming transactions * Fixs race condition on loadStore Fixs check for updates address null validation * Adds ensureOnceAsync for getGnosisSafeInstanceAt Adds batch request for safe params * Removes unnecessary checkAndUpdateSafe from checkForUpdates, now the safe gets updated when a transaction arrives * Fixs ensureOnce/memoization * refactor: make a generic generateBatchRequest method Create a generic method to easily build web3 batch requests * refactor: use `generateBatchRequest` in `getTokensBalances` * Removes .toJS in edit entry * Removes web3 from sendTransactions Removes pascal case FetchTokens * Replaces /layout import * Replaces CheckForUpdates component with useCheckForUpdates hook * Makes FetchTokens a hook * Removes getSafeParamsBatch, now the safes gets the data using the generic generateBatchRequests * Replaces INITIAL_STATUS with INITIAL_STATE * Replaces regex Adds spaces before return * Adds wrapInSuspense * Runs prettier * Makes checkAndUpdateSafe use generateBatchRequests * Makes checkAndUpdateSafe use generateBatchRequests * Fixs check for updates with null address * Fixs transaction details getNameFromAddressBook * Fixes zIndex between cookies banner and transaction details * fix: cast returned values to number Original code was expecting a BN instance, now it's a plain string. * Fix replace owner name * Fix race condition with adbk load * Fixes replaces owner * Fixs apps * Moved hooks into own folder * Moved LoadStore to routes.js Refactors LoadStore as Hook Move LoadStore to hooks folder * Moves useLoadStore to safes/index * Revert loadStore place change * Fixes bug with fetchEtherBalance that causes updateSafe to be called * remove useLoadStore, add useAnalytics hook * remove React.memo from SafeView * Reverts removing useLoadStore in order to maintain the consistency of the code * rewrite useLoadStore in a more hook-y way, rename it to useLoadSafe * Removes unnecessary setSafeLoaded * Removes unnecessary safeLoaded * fix: Coins values and balances The app was retrieving ERC20 tokens information from 3 different endpoints. - One from `balance/` to have the list updated - another from `balance/usd` to have the values in USD - the last one from the blockchain, to update the balances This was all simplified to `balance/usd`. Also, added a `currencyRate` to be updated when the currency is modified. The value calculation happens on a component level, so when the `balanceUsd` value is modified, the value is properly reflected on the screen. Refactored `activateTokensByBalance` to `fetchSafeTokens`, as this was doing quite more than just _activating_ and also added the `currencyList` calculation in it, so everything is updated when `balance/usd` endpoint is requested. * fix: Balance screen Collectibles weren't loading when clicking on the link Also, refactored setState usage, to properly update current state * fix: featuresEnabled undefined * fix: add/activate newly received tokens * fix: NaN Values in Coins for a newly loaded Safe Was failing to set a default value for the `currencyRate` * fix: Settings fails to load if `owners` is not loaded into store Added a `Loader` until the required Safe's data is loaded into store. * fix: prefetch txs data When building the Txs list, we requested data for every tx what was translated into several RPC calls. Now by _batchRequesting_ all the information on beforehand, Safe's loading is a bit faster. * fix: prevent requesting safe, when there's no safe available in the store * enhancement: fetch tokens when loading safe By doing this, when loading a safe in the balance screen we will have tokens immediately loaded into the coins list * fix: load collectibles when switch to collectibles screen Collectibles weren't loaded when clicking menu link for a newly loaded safe. Now every switch to the collectible's screen will trigger a fetch for collectibles. * fix: fetch only if safe is ready Co-authored-by: fernandomg <fernando.greco@gmail.com> Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com> * Fix (#777) * fix: batchRequest params order * fix: execute decodeParams for all sendTokenTxs * fix: proper amount display for tx in TxTable * Uses formatAmount * Removes unused code Fixs params props safe address form * Fixs composeValidators Adds composeValidators for apps section * Makes composeValidatorsApps a wrapper * Moves composeValidatorsApps to managesApps.js * Desktop app (#745) * Set up electron app * Update dependencies * Update package.json * Added https support * Add support for Ledger * Updated certs * Added auto updates messages * Update auto-updater method * Update package.json * Added build resources * Update preload * Update Ledger method on mac * Update build * Merge with develop * Added support for Portis * Fix electron error and updater * Update auto updater * Fix dependencies * Merge with develop * Change auto update functionality * Edit package.json and added github actions * Updated github actions * Fixed Torus + Update github actions * Updated release.yml * Try only ubuntu * Update package.json * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * Updated safe-contracts * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * Updated deploy branch * Updated script Co-authored-by: Mati Dastugue <matias.dastugue@mercadolibre.com> * Update yarn script + SAFE_APPS env variable * Converts custom token address to checksum version (#793) * SafeTxGas calculation: Add check for openethereum/parity revert messages (#788) * add check for openethereum/parity revert messages * fix isEstimationSuccessful check * fix estimation check if revert msg is from openethereum * Issue 796 (#807) * consume gnosis componentes from npm * set safe-apps url from environment variable * fix apps padding and border radius * Apps updates * update disclaimer * fix Loader in TXList * Fix invalid origin Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> * (Feature) Tx Table amount notations (#812) * Fix master conflicts (#819) * v2.0.0 (#806) * Bug: Invalid V in signature with eth_sign (#728) * Fix invalid V with metamask/ledger * DONT FORGET TO REVERT BEFORE MERGING: test deployment * DONT FORGET TO REVERT BEFORE MERGING 2: test deployment * Revert "DONT FORGET TO REVERT BEFORE MERGING 2: test deployment" This reverts commit 8331f2a78f7fc8f53eb893899f16edd8238c68ff. * Revert "DONT FORGET TO REVERT BEFORE MERGING: test deployment" This reverts commit 03b81e31820ce4fe078a7131c2f0caa2af4870ac. * BUG: Only injected providers are cached as last used provider (#733) * cache every used provider, not only injected one * package json update * (Fix) Adapt app to back-end changes (#736) * refactor: Set success status to `201` (CREATED) * refactor: return `null` when there's no latestTx * (Fix) Transaction not automatically executed (#716) * feature: action/reducer to UPDATE_SAFE_NONCE * refactor: when processing txs returned from backend, extract latest tx nonce value and store it in the safe's state * chore: update `yarn.lock` * refactor: `UPDATE_SAFE_THRESHOLD` and `UPDATE_SAFE_NONCE` discarded in favor of `UPDATE_SAFE` * refactor: use `SAFE_REDUCER_ID` constant * refactor: remove `updateSafeNonce` file * (Fix) Change the order of the upgrade methods lookup (#740) * fix: change the order of the upgrade methods lookup The `isUpgradeTransaction` method was looking for the methods in an wrong order (#599). The proper order was set in #610, but `isUpgradeTransaction` wasn't updated. * fix: contract upgrade version lookup * Feature: Use eth_sign for hardware wallets connected via onboard.js (#742) * Use eth_sign for hardware wallets * install onboard.js with fix from forked repo * rebuild yarn.lock to fix cached onboard * update bnc-onboard * update package json (#743) * (Fix) Properly decode threshold value in tx details (#749) * fix: Display new threshold value when changing its value There was a typo for the `changeThreshold` action fixes #746 * refactor: use a constant for safe methods names * fix: check for `decimals` method in transferredTokens (#748) Previously we were looking for `decimals` hash in the contract `code`. There are some contracts like USDC who happen to be behind a FiatTokenProxy, making it upgradable. By directly calling the `decimals()` method, we interact with the contract and can be sure that the `decimals()` method is present. fixes #678 * Bug #747: Don't use getLastTxNonce to fetch safe nonce (#750) * don't use getLastTxNonce to fetch safe nonce * fetch safe nonce in checkAndUpdateSafe * checkAndUpdateSafe refactor * remove nonce update logic from UPDATE_SAFE reducer * handle the case when localSafe returns undefined * handle the case when localSafe returns undefined in buildTransactionFrom * bump package json version to 1.9.4 * Issue-595: Apps config from Manifest (#715) * getting apps info from its manifest * Consume app info from manifest in Apps list, Transactions and Toast * fixes * navigate to TX Tab with an app makes a TX * (Fix) If backend returns `null` for addresses the Transaction ca… (#718) This tends to solve any possible issue that there may be in the tx execution for the `gasToken` and `refundReceiver` nullish values. fixes #573 * #751 fix - Replaces decimals from backend with decimals from blockchain (#755) * Replaces decimals from backend with decimals from blockchain * Removes fetching again token info from blockchain Fixs decimals cast, now we force to move from bignumber to number For data already wrong stored as string we remove it to force fetching again the decimals * Fixs missing symbol * Add description comment * Added Unilogin provider + support for legacy paths (#719) * Added unilogin provier + support for legacy path * Bump onboardjs version * fallback to displaying custom tx when we fail to fetch token info (#767) * Create release.yml Created script for building desktop app * Feature #322: Set safeTxGas for newly created transactions (#752) * Set safeTxGas for newly created transactions * extending estimation for nested calls WIP * messing up things to implement safeTxGas estimation * simplifying base gas calculations * remove eslint disable * messing things up to make things work * bring estimateData back * pass payload to requiredTxGas * pass esimateData to estimateDataGasCosts * remove console log * use batch requests to estimate safeTxGas * use const for txGasEstimation * check the response in request simultion * sidebar fix * remove for loop * Manage Apps (#765) * getting apps info from its manifest * Consume app info from manifest in Apps list, Transactions and Toast * fixes * navigate to TX Tab with an app makes a TX * ManageApps partial implementation * update safe-react-components * changes * apps validator * fix providedBy * TextField in addApp * fix checkbox error message * validation * adding app * Manage Apps * fix modal width * update package.json * update netlify url * fix modal widh * Set layout to Non-owners allowed error * some fixes * Apply suggestions from code review Co-Authored-By: lukasschor <lukas.schor@gnosis.pm> * review changes * fix condition * Legal Disclaimer * Better error message * update yarn.lock * Error message * review fixes * upgrade safe-react-components * show for all environments * Disclaimer changes * review changes * fix re-render * visual changes Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> Co-authored-by: lukasschor <lukas.schor@gnosis.pm> * fix scroll and fix margin layout * Add region to travis CI develop (#787) Enable region for s3 provider to allow upload development environment to different S3 regions * Feature/travis ci s3 region (#789) * Add region to travis CI develop Enable region for s3 provider to allow upload development environment to different S3 regions * Enable region for staging s3 providers * fix error on Wrapper * Add gnosis wc bridge to onboard.js wallets options array (#790) * Rename incoming-transactions url to incoming-transfers * Feature #587 - App performance improvement (#738) * Refactor Balances to functional component Removes Balances props in Layout.jsx * Replaces selectors that were using safeParamAddressSelector with safeParamAddressFromStateSelector to avoid the bug of non-loaded safe when called Also exports extendedTransactionsSelector to let the components use it * Refactors Transactions.jsx, replaces transactions.tsx with txsTable.jsx Removes all unused props from transactions.jsx Makes all childs of txsTable.jsx fetch the props they need instead of sharing all of them even if they are not used * Adds new selectors: safeNameSelector, safeNeedsUpdateSelector, safeCurrentVersionSelector * Removes unused props from layout to settings.jsx Removed props from the settings.jsx childs, now they fetch the values they need directly from the store * Removes unused redux connect * Adds safeEthBalanceSelector * Removes all the props from layout to settings * Refactor root and layout, extracts checkForUpdate and componentDidMount to components Extracts header and tabs from Layout.jsx * Makes routes.jsx use selectors instead of connect to unify the code * Loads tabs components using react suspense * Fixs warning when trying to update root component within loadStore.jsx Replaces safe with safeAddress selector in layout.jsx to reduce the unnecessary rendering Fixs setState in container.jsx * Fixs checkForUpdates fetchTokenBalances Adds FetchTokens.jsx in balances Adds safeFeaturesEnabledSelector * Fixs load addressbook action * Replaces safe with owners in manage owners * Improves buildSafe promises calls Improves the loadStorage calls * Fixs error "Uncaught (in promise) TypeError: Cannot read property 'includes' of undefined" * Extracts LoadStore from outside the router component to avoid re-loading the store Adds react lazy for Coins and Collectible tabs * Reduce the polling rate for fetching transactions * Removes unused actions.js Removes unused selector props * Fixes owners column selector usage * Fixes processTransaction usage * Optimize how the transaction list within the transactions tab are loaded * Fix lint error * Fix edit addressbook entry * Fixs show send coins modal * feature: batchRequest for incoming transactions * Fixs race condition on loadStore Fixs check for updates address null validation * Adds ensureOnceAsync for getGnosisSafeInstanceAt Adds batch request for safe params * Removes unnecessary checkAndUpdateSafe from checkForUpdates, now the safe gets updated when a transaction arrives * Fixs ensureOnce/memoization * refactor: make a generic generateBatchRequest method Create a generic method to easily build web3 batch requests * refactor: use `generateBatchRequest` in `getTokensBalances` * Removes .toJS in edit entry * Removes web3 from sendTransactions Removes pascal case FetchTokens * Replaces /layout import * Replaces CheckForUpdates component with useCheckForUpdates hook * Makes FetchTokens a hook * Removes getSafeParamsBatch, now the safes gets the data using the generic generateBatchRequests * Replaces INITIAL_STATUS with INITIAL_STATE * Replaces regex Adds spaces before return * Adds wrapInSuspense * Runs prettier * Makes checkAndUpdateSafe use generateBatchRequests * Makes checkAndUpdateSafe use generateBatchRequests * Fixs check for updates with null address * Fixs transaction details getNameFromAddressBook * Fixes zIndex between cookies banner and transaction details * fix: cast returned values to number Original code was expecting a BN instance, now it's a plain string. * Fix replace owner name * Fix race condition with adbk load * Fixes replaces owner * Fixs apps * Moved hooks into own folder * Moved LoadStore to routes.js Refactors LoadStore as Hook Move LoadStore to hooks folder * Moves useLoadStore to safes/index * Revert loadStore place change * Fixes bug with fetchEtherBalance that causes updateSafe to be called * remove useLoadStore, add useAnalytics hook * remove React.memo from SafeView * Reverts removing useLoadStore in order to maintain the consistency of the code * rewrite useLoadStore in a more hook-y way, rename it to useLoadSafe * Removes unnecessary setSafeLoaded * Removes unnecessary safeLoaded * fix: Coins values and balances The app was retrieving ERC20 tokens information from 3 different endpoints. - One from `balance/` to have the list updated - another from `balance/usd` to have the values in USD - the last one from the blockchain, to update the balances This was all simplified to `balance/usd`. Also, added a `currencyRate` to be updated when the currency is modified. The value calculation happens on a component level, so when the `balanceUsd` value is modified, the value is properly reflected on the screen. Refactored `activateTokensByBalance` to `fetchSafeTokens`, as this was doing quite more than just _activating_ and also added the `currencyList` calculation in it, so everything is updated when `balance/usd` endpoint is requested. * fix: Balance screen Collectibles weren't loading when clicking on the link Also, refactored setState usage, to properly update current state * fix: featuresEnabled undefined * fix: add/activate newly received tokens * fix: NaN Values in Coins for a newly loaded Safe Was failing to set a default value for the `currencyRate` * fix: Settings fails to load if `owners` is not loaded into store Added a `Loader` until the required Safe's data is loaded into store. * fix: prefetch txs data When building the Txs list, we requested data for every tx what was translated into several RPC calls. Now by _batchRequesting_ all the information on beforehand, Safe's loading is a bit faster. * fix: prevent requesting safe, when there's no safe available in the store * enhancement: fetch tokens when loading safe By doing this, when loading a safe in the balance screen we will have tokens immediately loaded into the coins list * fix: load collectibles when switch to collectibles screen Collectibles weren't loaded when clicking menu link for a newly loaded safe. Now every switch to the collectible's screen will trigger a fetch for collectibles. * fix: fetch only if safe is ready Co-authored-by: fernandomg <fernando.greco@gmail.com> Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com> * Fix (#777) * fix: batchRequest params order * fix: execute decodeParams for all sendTokenTxs * fix: proper amount display for tx in TxTable * Uses formatAmount * Removes unused code Fixs params props safe address form * Fixs composeValidators Adds composeValidators for apps section * Makes composeValidatorsApps a wrapper * Moves composeValidatorsApps to managesApps.js * Desktop app (#745) * Set up electron app * Update dependencies * Update package.json * Added https support * Add support for Ledger * Updated certs * Added auto updates messages * Update auto-updater method * Update package.json * Added build resources * Update preload * Update Ledger method on mac * Update build * Merge with develop * Added support for Portis * Fix electron error and updater * Update auto updater * Fix dependencies * Merge with develop * Change auto update functionality * Edit package.json and added github actions * Updated github actions * Fixed Torus + Update github actions * Updated release.yml * Try only ubuntu * Update package.json * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * Updated safe-contracts * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * v1.9.6 * Updated deploy branch * Updated script Co-authored-by: Mati Dastugue <matias.dastugue@mercadolibre.com> Co-authored-by: Fernando <fernando.greco@gmail.com> Co-authored-by: nicolas <nicosampler@users.noreply.github.com> Co-authored-by: Agustin Pane <agustin.pane@gmail.com> Co-authored-by: Mati Dastugue <matias.dastugue@altoros.com> Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> Co-authored-by: lukasschor <lukas.schor@gnosis.pm> Co-authored-by: David Albela Pérez <3659067+davidalbela@users.noreply.github.com> Co-authored-by: Uxio Fuentefria <uxio@gnosis.pm> Co-authored-by: Mati Dastugue <matias.dastugue@mercadolibre.com> * Update CI Desktop script * Update CI script for windows Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com> Co-authored-by: Fernando <fernando.greco@gmail.com> Co-authored-by: Agustin Pane <agustin.pane@gmail.com> Co-authored-by: Mati Dastugue <matias.dastugue@altoros.com> Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> Co-authored-by: lukasschor <lukas.schor@gnosis.pm> Co-authored-by: David Albela Pérez <3659067+davidalbela@users.noreply.github.com> Co-authored-by: Uxio Fuentefria <uxio@gnosis.pm> Co-authored-by: Mati Dastugue <matias.dastugue@mercadolibre.com> Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com> Co-authored-by: Fernando <fernando.greco@gmail.com> Co-authored-by: Agustin Pane <agustin.pane@gmail.com> Co-authored-by: Mati Dastugue <matias.dastugue@altoros.com> Co-authored-by: Agustín Longoni <agustin.longoni@altoros.com> Co-authored-by: lukasschor <lukas.schor@gnosis.pm> Co-authored-by: David Albela Pérez <3659067+davidalbela@users.noreply.github.com> Co-authored-by: Uxio Fuentefria <uxio@gnosis.pm> Co-authored-by: Mati Dastugue <matias.dastugue@mercadolibre.com>
This commit is contained in:
parent
c9affbb55f
commit
fbaaff524e
|
@ -137,8 +137,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
||||||
"@gnosis.pm/util-contracts": "2.0.6",
|
"@gnosis.pm/util-contracts": "2.0.6",
|
||||||
|
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#a057248",
|
||||||
"@ledgerhq/hw-transport-node-hid": "5.12.0",
|
"@ledgerhq/hw-transport-node-hid": "5.12.0",
|
||||||
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#71e6fed",
|
|
||||||
"@material-ui/core": "4.9.10",
|
"@material-ui/core": "4.9.10",
|
||||||
"@material-ui/icons": "4.9.1",
|
"@material-ui/icons": "4.9.1",
|
||||||
"@material-ui/lab": "4.0.0-alpha.39",
|
"@material-ui/lab": "4.0.0-alpha.39",
|
||||||
|
|
|
@ -4,7 +4,7 @@ import styled from 'styled-components'
|
||||||
export const Wrapper = styled.div`
|
export const Wrapper = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 245px auto;
|
grid-template-columns: 245px auto;
|
||||||
grid-template-rows: 500px;
|
grid-template-rows: 514px;
|
||||||
min-height: 525px;
|
min-height: 525px;
|
||||||
|
|
||||||
.background {
|
.background {
|
||||||
|
@ -33,6 +33,7 @@ export const Menu = styled.div.attrs(() => ({ className: 'background' }))`
|
||||||
export const Content = styled.div.attrs(() => ({ className: 'background' }))`
|
export const Content = styled.div.attrs(() => ({ className: 'background' }))`
|
||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
border-top-right-radius: 8px;
|
border-top-right-radius: 8px;
|
||||||
|
border-bottom-right-radius: 8px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,15 @@ export const estimateSafeTxGas = async (
|
||||||
gasLimit: txGasEstimation + dataGasEstimation + additionalGas,
|
gasLimit: txGasEstimation + dataGasEstimation + additionalGas,
|
||||||
},
|
},
|
||||||
(error, res) => {
|
(error, res) => {
|
||||||
|
// res.data check is for OpenEthereum/Parity revert messages format
|
||||||
|
const isOpenEthereumRevertMsg = res && typeof res.data === 'string'
|
||||||
|
|
||||||
|
const isEstimationSuccessful =
|
||||||
|
!error &&
|
||||||
|
((typeof res === 'string' && res !== '0x') || (isOpenEthereumRevertMsg && res.data.slice(9) !== '0x'))
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
success: error || res === '0x' ? false : true,
|
success: isEstimationSuccessful,
|
||||||
estimation: txGasEstimation + additionalGas,
|
estimation: txGasEstimation + additionalGas,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { type Token, makeToken } from '~/logic/tokens/store/model/token'
|
||||||
|
|
||||||
export const TOKEN_REDUCER_ID = 'tokens'
|
export const TOKEN_REDUCER_ID = 'tokens'
|
||||||
|
|
||||||
export type State = Map<string, Map<string, Token>>
|
export type State = Map<string, Token>
|
||||||
|
|
||||||
export default handleActions<State, *>(
|
export default handleActions<State, *>(
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const formatAmount = (number: string | number) => {
|
||||||
let numberFloat = parseFloat(number)
|
let numberFloat = parseFloat(number)
|
||||||
|
|
||||||
if (numberFloat === 0) {
|
if (numberFloat === 0) {
|
||||||
numberFloat = '0.000'
|
numberFloat = '0'
|
||||||
} else if (numberFloat < 0.001) {
|
} else if (numberFloat < 0.001) {
|
||||||
numberFloat = '< 0.001'
|
numberFloat = '< 0.001'
|
||||||
} else if (numberFloat < 1000) {
|
} else if (numberFloat < 1000) {
|
||||||
|
|
|
@ -26,6 +26,8 @@ const APPS_STORAGE_KEY = 'APPS_STORAGE_KEY'
|
||||||
const APPS_LEGAL_DISCLAIMER_STORAGE_KEY = 'APPS_LEGAL_DISCLAIMER_STORAGE_KEY'
|
const APPS_LEGAL_DISCLAIMER_STORAGE_KEY = 'APPS_LEGAL_DISCLAIMER_STORAGE_KEY'
|
||||||
|
|
||||||
const StyledIframe = styled.iframe`
|
const StyledIframe = styled.iframe`
|
||||||
|
padding: 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: ${(props) => (props.shouldDisplay ? 'block' : 'none')};
|
display: ${(props) => (props.shouldDisplay ? 'block' : 'none')};
|
||||||
|
@ -36,7 +38,6 @@ const Centered = styled.div`
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`
|
`
|
||||||
|
|
||||||
const operations = {
|
const operations = {
|
||||||
SEND_TRANSACTIONS: 'SEND_TRANSACTIONS',
|
SEND_TRANSACTIONS: 'SEND_TRANSACTIONS',
|
||||||
ON_SAFE_INFO: 'ON_SAFE_INFO',
|
ON_SAFE_INFO: 'ON_SAFE_INFO',
|
||||||
|
@ -151,7 +152,7 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
<a href="https://gnosis-safe.io/terms" rel="noopener noreferrer" target="_blank">
|
<a href="https://gnosis-safe.io/terms" rel="noopener noreferrer" target="_blank">
|
||||||
Terms
|
Terms
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
and this Disclaimer, and agree to be bound by .
|
and this Disclaimer, and agree to be bound by them.
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,12 @@ import axios from 'axios'
|
||||||
|
|
||||||
import appsIconSvg from '~/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
import appsIconSvg from '~/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg'
|
||||||
|
|
||||||
export const GNOSIS_APPS_URL = 'https://gnosis-apps.netlify.app'
|
export const staticAppsList = [
|
||||||
|
{ url: `${process.env.REACT_APP_GNOSIS_APPS_URL}/compound`, disabled: false },
|
||||||
const appsUrl = process.env.REACT_APP_GNOSIS_APPS_URL ? process.env.REACT_APP_GNOSIS_APPS_URL : GNOSIS_APPS_URL
|
{ url: `${process.env.REACT_APP_GNOSIS_APPS_URL}/uniswap`, disabled: false },
|
||||||
export const staticAppsList = [{ url: `${appsUrl}/compound`, disabled: false }]
|
{ url: `${process.env.REACT_APP_GNOSIS_APPS_URL}/nexus-mutual`, disabled: false },
|
||||||
|
{ url: `${process.env.REACT_APP_GNOSIS_APPS_URL}/ens`, disabled: false },
|
||||||
|
]
|
||||||
|
|
||||||
export const getAppInfoFromOrigin = (origin: string) => {
|
export const getAppInfoFromOrigin = (origin: string) => {
|
||||||
try {
|
try {
|
||||||
|
@ -18,13 +20,17 @@ export const getAppInfoFromOrigin = (origin: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAppInfoFromUrl = async (appUrl: string) => {
|
export const getAppInfoFromUrl = async (appUrl: string) => {
|
||||||
|
let res = { id: undefined, url: cleanedUpAppUrl, name: 'unknown', iconUrl: appsIconSvg, error: true }
|
||||||
|
|
||||||
|
if (!appUrl) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
let cleanedUpAppUrl = appUrl.trim()
|
let cleanedUpAppUrl = appUrl.trim()
|
||||||
if (cleanedUpAppUrl.substr(-1) === '/') {
|
if (cleanedUpAppUrl.substr(-1) === '/') {
|
||||||
cleanedUpAppUrl = cleanedUpAppUrl.substr(0, cleanedUpAppUrl.length - 1)
|
cleanedUpAppUrl = cleanedUpAppUrl.substr(0, cleanedUpAppUrl.length - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = { id: undefined, url: cleanedUpAppUrl, name: 'unknown', iconUrl: appsIconSvg, error: true }
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const appInfo = await axios.get(`${cleanedUpAppUrl}/manifest.json`)
|
const appInfo = await axios.get(`${cleanedUpAppUrl}/manifest.json`)
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import Img from '~/components/layout/Img'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import Row from '~/components/layout/Row'
|
import Row from '~/components/layout/Row'
|
||||||
import { type Token, type TokenProps } from '~/logic/tokens/store/model/token'
|
import { type Token, type TokenProps } from '~/logic/tokens/store/model/token'
|
||||||
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
|
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
|
||||||
|
|
||||||
export const ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID = 'add-custom-token-address-input'
|
export const ADD_CUSTOM_TOKEN_ADDRESS_INPUT_TEST_ID = 'add-custom-token-address-input'
|
||||||
|
@ -64,8 +65,9 @@ const AddCustomToken = (props: Props) => {
|
||||||
const [formValues, setFormValues] = useState(INITIAL_FORM_STATE)
|
const [formValues, setFormValues] = useState(INITIAL_FORM_STATE)
|
||||||
|
|
||||||
const handleSubmit = (values) => {
|
const handleSubmit = (values) => {
|
||||||
|
const address = getWeb3().utils.toChecksumAddress(values.address)
|
||||||
const token = {
|
const token = {
|
||||||
address: values.address,
|
address,
|
||||||
decimals: values.decimals,
|
decimals: values.decimals,
|
||||||
symbol: values.symbol,
|
symbol: values.symbol,
|
||||||
name: values.symbol,
|
name: values.symbol,
|
||||||
|
|
|
@ -49,7 +49,7 @@ const IncomingTxDescription = ({ tx }: Props) => {
|
||||||
const txFromName = getNameFromAddressBook(tx.from)
|
const txFromName = getNameFromAddressBook(tx.from)
|
||||||
return (
|
return (
|
||||||
<Block className={classes.txDataContainer}>
|
<Block className={classes.txDataContainer}>
|
||||||
<TransferDescription from={tx.from} txFromName={txFromName} value={getIncomingTxAmount(tx)} />
|
<TransferDescription from={tx.from} txFromName={txFromName} value={getIncomingTxAmount(tx, false)} />
|
||||||
</Block>
|
</Block>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ const TxDescription = ({ classes, tx }: Props) => {
|
||||||
removedOwner,
|
removedOwner,
|
||||||
upgradeTx,
|
upgradeTx,
|
||||||
} = getTxData(tx)
|
} = getTxData(tx)
|
||||||
const amount = getTxAmount(tx)
|
const amount = getTxAmount(tx, false)
|
||||||
return (
|
return (
|
||||||
<Block className={classes.txDataContainer}>
|
<Block className={classes.txDataContainer}>
|
||||||
{modifySettingsTx && action && (
|
{modifySettingsTx && action && (
|
||||||
|
|
|
@ -41,8 +41,9 @@ const ExpandedTx = ({ cancelTx, tx }: Props) => {
|
||||||
const [openModal, setOpenModal] = useState<OpenModal>(null)
|
const [openModal, setOpenModal] = useState<OpenModal>(null)
|
||||||
const openApproveModal = () => setOpenModal('approveTx')
|
const openApproveModal = () => setOpenModal('approveTx')
|
||||||
const closeModal = () => setOpenModal(null)
|
const closeModal = () => setOpenModal(null)
|
||||||
const thresholdReached = !INCOMING_TX_TYPES.includes(tx.type) && threshold <= tx.confirmations.size
|
const isIncomingTx = !!INCOMING_TX_TYPES[tx.type]
|
||||||
const canExecute = !INCOMING_TX_TYPES.includes(tx.type) && nonce === tx.nonce
|
const thresholdReached = !isIncomingTx && threshold <= tx.confirmations.size
|
||||||
|
const canExecute = !isIncomingTx && nonce === tx.nonce
|
||||||
const cancelThresholdReached = !!cancelTx && threshold <= cancelTx.confirmations.size
|
const cancelThresholdReached = !!cancelTx && threshold <= cancelTx.confirmations.size
|
||||||
const canExecuteCancel = nonce === tx.nonce
|
const canExecuteCancel = nonce === tx.nonce
|
||||||
|
|
||||||
|
@ -59,22 +60,22 @@ const ExpandedTx = ({ cancelTx, tx }: Props) => {
|
||||||
<Block className={classes.expandedTxBlock}>
|
<Block className={classes.expandedTxBlock}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col layout="column" xs={6}>
|
<Col layout="column" xs={6}>
|
||||||
<Block
|
<Block className={cn(classes.txDataContainer, isIncomingTx && classes.incomingTxBlock)}>
|
||||||
className={cn(classes.txDataContainer, INCOMING_TX_TYPES.includes(tx.type) && classes.incomingTxBlock)}
|
|
||||||
>
|
|
||||||
<Block align="left" className={classes.txData}>
|
<Block align="left" className={classes.txData}>
|
||||||
<Bold className={classes.txHash}>Hash:</Bold>
|
<Bold className={classes.txHash}>Hash:</Bold>
|
||||||
{tx.executionTxHash ? <EtherScanLink cut={8} type="tx" value={tx.executionTxHash} /> : 'n/a'}
|
{tx.executionTxHash ? <EtherScanLink cut={8} type="tx" value={tx.executionTxHash} /> : 'n/a'}
|
||||||
</Block>
|
</Block>
|
||||||
|
{!isIncomingTx && (
|
||||||
<Paragraph noMargin>
|
<Paragraph noMargin>
|
||||||
<Bold>Nonce: </Bold>
|
<Bold>Nonce: </Bold>
|
||||||
<Span>{tx.nonce}</Span>
|
<Span>{tx.nonce}</Span>
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
|
)}
|
||||||
<Paragraph noMargin>
|
<Paragraph noMargin>
|
||||||
<Bold>Fee: </Bold>
|
<Bold>Fee: </Bold>
|
||||||
{tx.fee ? tx.fee : 'n/a'}
|
{tx.fee ? tx.fee : 'n/a'}
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
{INCOMING_TX_TYPES.includes(tx.type) ? (
|
{isIncomingTx ? (
|
||||||
<>
|
<>
|
||||||
<Paragraph noMargin>
|
<Paragraph noMargin>
|
||||||
<Bold>Created: </Bold>
|
<Bold>Created: </Bold>
|
||||||
|
@ -113,9 +114,9 @@ const ExpandedTx = ({ cancelTx, tx }: Props) => {
|
||||||
)}
|
)}
|
||||||
</Block>
|
</Block>
|
||||||
<Hairline />
|
<Hairline />
|
||||||
{INCOMING_TX_TYPES.includes(tx.type) ? <IncomingTxDescription tx={tx} /> : <TxDescription tx={tx} />}
|
{isIncomingTx ? <IncomingTxDescription tx={tx} /> : <TxDescription tx={tx} />}
|
||||||
</Col>
|
</Col>
|
||||||
{!INCOMING_TX_TYPES.includes(tx.type) && (
|
{!isIncomingTx && (
|
||||||
<OwnersColumn
|
<OwnersColumn
|
||||||
cancelThresholdReached={cancelThresholdReached}
|
cancelThresholdReached={cancelThresholdReached}
|
||||||
cancelTx={cancelTx}
|
cancelTx={cancelTx}
|
||||||
|
|
|
@ -40,6 +40,7 @@ const TxType = ({ origin, txType }: { txType: TransactionType, origin: string |
|
||||||
const parsedOrigin = getAppInfoFromOrigin(origin)
|
const parsedOrigin = getAppInfoFromOrigin(origin)
|
||||||
if (!parsedOrigin) {
|
if (!parsedOrigin) {
|
||||||
setForceCustom(true)
|
setForceCustom(true)
|
||||||
|
setLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const appInfo = await getAppInfoFromUrl(parsedOrigin.url)
|
const appInfo = await getAppInfoFromUrl(parsedOrigin.url)
|
||||||
|
@ -52,7 +53,7 @@ const TxType = ({ origin, txType }: { txType: TransactionType, origin: string |
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppInfo()
|
getAppInfo()
|
||||||
}, [txType])
|
}, [origin, txType])
|
||||||
|
|
||||||
if (forceCustom || !origin) {
|
if (forceCustom || !origin) {
|
||||||
return <IconText iconUrl={typeToIcon[txType]} text={typeToLabel[txType]} />
|
return <IconText iconUrl={typeToIcon[txType]} text={typeToLabel[txType]} />
|
||||||
|
|
|
@ -9,7 +9,6 @@ import TxType from './TxType'
|
||||||
import { type Column } from '~/components/Table/TableHead'
|
import { type Column } from '~/components/Table/TableHead'
|
||||||
import { type SortRow, buildOrderFieldFrom } from '~/components/Table/sorting'
|
import { type SortRow, buildOrderFieldFrom } from '~/components/Table/sorting'
|
||||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
|
||||||
import { INCOMING_TX_TYPES, type IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
import { INCOMING_TX_TYPES, type IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
|
||||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
|
||||||
|
@ -34,29 +33,40 @@ type TxData = {
|
||||||
|
|
||||||
export const formatDate = (date: string): string => format(parseISO(date), 'MMM d, yyyy - HH:mm:ss')
|
export const formatDate = (date: string): string => format(parseISO(date), 'MMM d, yyyy - HH:mm:ss')
|
||||||
|
|
||||||
export const getIncomingTxAmount = (tx: IncomingTransaction) => {
|
type TxValues = {
|
||||||
const txAmount = tx.value ? `${new BigNumber(tx.value).div(`1e${tx.decimals}`).toFixed()}` : 'n/a'
|
value?: string | number,
|
||||||
return `${txAmount} ${tx.symbol || 'n/a'}`
|
decimals?: string | number,
|
||||||
|
symbol?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTxAmount = (tx: Transaction) => {
|
const NOT_AVAILABLE = 'n/a'
|
||||||
const web3 = getWeb3()
|
|
||||||
const { fromWei, toBN } = web3.utils
|
|
||||||
|
|
||||||
let txAmount = 'n/a'
|
const getAmountWithSymbol = ({ decimals = 0, symbol = NOT_AVAILABLE, value }: TxValues, formatted = false) => {
|
||||||
|
const nonFormattedValue = BigNumber(value).times(`1e-${decimals}`).toFixed()
|
||||||
|
const finalValue = formatted ? formatAmount(nonFormattedValue).toString() : nonFormattedValue
|
||||||
|
const txAmount = finalValue === 'NaN' ? NOT_AVAILABLE : finalValue
|
||||||
|
|
||||||
if (tx.isTokenTransfer && tx.decodedParams) {
|
return `${txAmount} ${symbol}`
|
||||||
const tokenDecimals = tx.decimals.toNumber ? tx.decimals.toNumber() : tx.decimals
|
|
||||||
txAmount = `${formatAmount(
|
|
||||||
BigNumber(tx.decodedParams.value)
|
|
||||||
.div(10 ** tokenDecimals)
|
|
||||||
.toString(),
|
|
||||||
)} ${tx.symbol}`
|
|
||||||
} else if (Number(tx.value) > 0) {
|
|
||||||
txAmount = `${fromWei(toBN(tx.value), 'ether')} ${tx.symbol}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return txAmount
|
export const getIncomingTxAmount = (tx: IncomingTransaction, formatted: boolean = true) => {
|
||||||
|
// simple workaround to avoid displaying unexpected values for incoming NFT transfer
|
||||||
|
if (INCOMING_TX_TYPES[tx.type] === INCOMING_TX_TYPES.ERC721_TRANSFER) {
|
||||||
|
return `1 ${tx.symbol}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAmountWithSymbol(tx, formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTxAmount = (tx: Transaction, formatted: boolean = true) => {
|
||||||
|
const { decimals = 18, decodedParams, isTokenTransfer, symbol } = tx
|
||||||
|
const { value } = isTokenTransfer && decodedParams && decodedParams.value ? decodedParams : tx
|
||||||
|
|
||||||
|
if (!isTokenTransfer && !(Number(value) > 0)) {
|
||||||
|
return NOT_AVAILABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
return getAmountWithSymbol({ decimals, symbol, value }, formatted)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TransactionRow = SortRow<TxData>
|
export type TransactionRow = SortRow<TxData>
|
||||||
|
@ -106,7 +116,7 @@ export const getTxTableData = (
|
||||||
const cancelTxsByNonce = cancelTxs.reduce((acc, tx) => acc.set(tx.nonce, tx), Map())
|
const cancelTxsByNonce = cancelTxs.reduce((acc, tx) => acc.set(tx.nonce, tx), Map())
|
||||||
|
|
||||||
return transactions.map((tx) => {
|
return transactions.map((tx) => {
|
||||||
if (INCOMING_TX_TYPES.includes(tx.type)) {
|
if (INCOMING_TX_TYPES[tx.type]) {
|
||||||
return getIncomingTxTableData(tx)
|
return getIncomingTxTableData(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,12 +76,12 @@ type IncomingTxServiceModel = {
|
||||||
|
|
||||||
export const buildTransactionFrom = async (
|
export const buildTransactionFrom = async (
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
tx: TxServiceModel,
|
|
||||||
knownTokens,
|
knownTokens,
|
||||||
|
tx: TxServiceModel,
|
||||||
|
txTokenCode,
|
||||||
txTokenDecimals,
|
txTokenDecimals,
|
||||||
txTokenSymbol,
|
|
||||||
txTokenName,
|
txTokenName,
|
||||||
code,
|
txTokenSymbol,
|
||||||
): Promise<Transaction> => {
|
): Promise<Transaction> => {
|
||||||
const localSafe = await getLocalSafe(safeAddress)
|
const localSafe = await getLocalSafe(safeAddress)
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ export const buildTransactionFrom = async (
|
||||||
const modifySettingsTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !!tx.data
|
const modifySettingsTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !!tx.data
|
||||||
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
const cancellationTx = sameAddress(tx.to, safeAddress) && Number(tx.value) === 0 && !tx.data
|
||||||
const isERC721Token =
|
const isERC721Token =
|
||||||
(code && code.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH)) ||
|
(txTokenCode && txTokenCode.includes(SAFE_TRANSFER_FROM_WITHOUT_DATA_HASH)) ||
|
||||||
(isTokenTransfer(tx.data, Number(tx.value)) && !knownTokens.get(tx.to) && txTokenDecimals !== null)
|
(isTokenTransfer(tx.data, Number(tx.value)) && !knownTokens.get(tx.to) && txTokenDecimals !== null)
|
||||||
let isSendTokenTx = !isERC721Token && isTokenTransfer(tx.data, Number(tx.value))
|
let isSendTokenTx = !isERC721Token && isTokenTransfer(tx.data, Number(tx.value))
|
||||||
const isMultiSendTx = isMultisendTransaction(tx.data, Number(tx.value))
|
const isMultiSendTx = isMultisendTransaction(tx.data, Number(tx.value))
|
||||||
|
@ -118,7 +118,7 @@ export const buildTransactionFrom = async (
|
||||||
let refundParams = null
|
let refundParams = null
|
||||||
if (tx.gasPrice > 0) {
|
if (tx.gasPrice > 0) {
|
||||||
const refundSymbol = txTokenSymbol || 'ETH'
|
const refundSymbol = txTokenSymbol || 'ETH'
|
||||||
const decimals = txTokenName || 18
|
const decimals = txTokenDecimals || 18
|
||||||
const feeString = (tx.gasPrice * (tx.baseGas + tx.safeTxGas)).toString().padStart(decimals, 0)
|
const feeString = (tx.gasPrice * (tx.baseGas + tx.safeTxGas)).toString().padStart(decimals, 0)
|
||||||
const whole = feeString.slice(0, feeString.length - decimals) || '0'
|
const whole = feeString.slice(0, feeString.length - decimals) || '0'
|
||||||
const fraction = feeString.slice(feeString.length - decimals)
|
const fraction = feeString.slice(feeString.length - decimals)
|
||||||
|
@ -230,8 +230,8 @@ const addMockSafeCreationTx = (safeAddress): Array<TxServiceModel> => [
|
||||||
const batchRequestTxsData = (txs: any[]) => {
|
const batchRequestTxsData = (txs: any[]) => {
|
||||||
const web3Batch = new web3.BatchRequest()
|
const web3Batch = new web3.BatchRequest()
|
||||||
|
|
||||||
const whenTxsValues = txs.map((tx) => {
|
const txsTokenInfo = txs.map((tx) => {
|
||||||
const methods = ['decimals', { method: 'getCode', type: 'eth', args: [tx.to] }, 'symbol', 'name']
|
const methods = [{ method: 'getCode', type: 'eth', args: [tx.to] }, 'decimals', 'name', 'symbol']
|
||||||
return generateBatchRequests({
|
return generateBatchRequests({
|
||||||
abi: ERC20Detailed.abi,
|
abi: ERC20Detailed.abi,
|
||||||
address: tx.to,
|
address: tx.to,
|
||||||
|
@ -243,7 +243,7 @@ const batchRequestTxsData = (txs: any[]) => {
|
||||||
|
|
||||||
web3Batch.execute()
|
web3Batch.execute()
|
||||||
|
|
||||||
return Promise.all(whenTxsValues)
|
return Promise.all(txsTokenInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const batchRequestIncomingTxsData = (txs: IncomingTxServiceModel[]) => {
|
const batchRequestIncomingTxsData = (txs: IncomingTxServiceModel[]) => {
|
||||||
|
@ -341,9 +341,15 @@ export const loadSafeTransactions = async (safeAddress: string, getState: GetSta
|
||||||
const txsWithData = await batchRequestTxsData(transactions)
|
const txsWithData = await batchRequestTxsData(transactions)
|
||||||
// In case that the etags don't match, we parse the new transactions and save them to the cache
|
// In case that the etags don't match, we parse the new transactions and save them to the cache
|
||||||
const txsRecord: Array<RecordInstance<TransactionProps>> = await Promise.all(
|
const txsRecord: Array<RecordInstance<TransactionProps>> = await Promise.all(
|
||||||
txsWithData.map(([tx: TxServiceModel, decimals, code, symbol, name]) =>
|
txsWithData.map(([tx: TxServiceModel, code, decimals, name, symbol]) => {
|
||||||
buildTransactionFrom(safeAddress, tx, knownTokens, decimals, symbol, name, code),
|
const knownToken = knownTokens.get(tx.to)
|
||||||
),
|
|
||||||
|
if (knownToken) {
|
||||||
|
;({ decimals, name, symbol } = knownToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildTransactionFrom(safeAddress, knownTokens, tx, code, decimals, name, symbol)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
const groupedTxs = List(txsRecord).groupBy((tx) => (tx.get('cancellationTx') ? 'cancel' : 'outgoing'))
|
const groupedTxs = List(txsRecord).groupBy((tx) => (tx.get('cancellationTx') ? 'cancel' : 'outgoing'))
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
import { Record } from 'immutable'
|
import { Record } from 'immutable'
|
||||||
import type { RecordFactory, RecordOf } from 'immutable'
|
import type { RecordFactory, RecordOf } from 'immutable'
|
||||||
|
|
||||||
export const INCOMING_TX_TYPES = ['INCOMING', 'ERC721_TRANSFER', 'ERC20_TRANSFER', 'ETHER_TRANSFER']
|
export const INCOMING_TX_TYPES = {
|
||||||
|
INCOMING: 'INCOMING',
|
||||||
|
ERC721_TRANSFER: 'ERC721_TRANSFER',
|
||||||
|
ERC20_TRANSFER: 'ERC20_TRANSFER',
|
||||||
|
ETHER_TRANSFER: 'ETHER_TRANSFER',
|
||||||
|
}
|
||||||
|
|
||||||
export type IncomingTransactionProps = {
|
export type IncomingTransactionProps = {
|
||||||
blockNumber: number,
|
blockNumber: number,
|
||||||
|
|
Loading…
Reference in New Issue