Tech debt: Add types for contracts (#1118)

* typechain wip

* add types for multisend

* type definitions improvements

* type safe contract in estimateTxGasCosts

* contract type definitions wip

* SafeInstance truffle -> web3 migration

* fix calls for version

* transactions/send enhancements

* fix safe recor owner type

* Stepper type definitions wip

* dep bump

* stepper types wip

* refactoring stepper component to fix bug in load safe form

* stepper types wip, addressbook reducer types wip

* finally make it work

* Fix ownerlist component hook in load safe

* dep bump

* dep bump

* rollback types/history

* add types for gas calc

* debugging...

* fix using RO web3 for sending txs

* update package.json generate-types command

* add ts-ignore for stepperpage

* db

* dep bump

* as unknown as AbiItem -> as AbiItem[]

* use optional chaining for isExecution in gas esimations

* abiITem -> AbiItem[]

* fix safeVersion utils tests

* fix imports, put upgradeSafe test close to the actual code

* add comment about ts-ignore usage

* downgrade web3 version
This commit is contained in:
Mikhail Mikheev 2020-08-01 02:26:10 +04:00 committed by GitHub
parent 24dffd53da
commit 86cbd94b0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 1038 additions and 792 deletions

3
.gitignore vendored
View File

@ -9,4 +9,5 @@ electron-builder.yml
/.yalc
yalc.lock
# testing
/coverage
/coverage/
src/types/contracts/

View File

@ -26,9 +26,11 @@
"electron-build": "electron-builder --mac --windows --linux",
"electron-dev": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron .\"",
"format:staged": "lint-staged",
"generate-types": "yarn generate-types:contracts",
"generate-types:contracts": "typechain --target=web3-v1 --outDir './src/types/contracts' './node_modules/@gnosis.pm/safe-contracts/build/contracts/*.json'",
"lint:check": "eslint './src/**/*.{js,jsx,ts,tsx}'",
"lint:fix": "yarn lint:check --fix",
"postinstall": "electron-builder install-app-deps",
"postinstall": "electron-builder install-app-deps && yarn generate-types",
"preelectron-pack": "yarn build",
"prettier:check": "yarn prettier --check",
"prettier:fix": "yarn prettier --write",
@ -165,7 +167,7 @@
"@ledgerhq/hw-transport-node-hid": "5.19.1",
"@material-ui/core": "4.11.0",
"@material-ui/icons": "4.9.1",
"@material-ui/lab": "4.0.0-alpha.39",
"@material-ui/lab": "4.0.0-alpha.56",
"@openzeppelin/contracts": "3.1.0",
"async-sema": "^3.1.0",
"axios": "0.19.2",
@ -183,6 +185,7 @@
"electron-updater": "4.3.1",
"eth-sig-util": "^2.5.3",
"ethereum-blockies-base64": "^1.0.2",
"ethereumjs-abi": "0.6.8",
"exponential-backoff": "^3.0.1",
"express": "^4.17.1",
"final-form": "^4.20.1",
@ -206,7 +209,7 @@
"react-ga": "3.1.2",
"react-hot-loader": "4.12.21",
"react-qr-reader": "^2.2.1",
"react-redux": "7.2.0",
"react-redux": "7.2.1",
"react-router-dom": "5.2.0",
"react-scripts": "^3.4.1",
"react-window": "^1.8.5",
@ -218,23 +221,27 @@
"semver": "7.3.2",
"styled-components": "^5.1.1",
"truffle-contract": "4.0.31",
"web3": "1.2.11"
"web3": "1.2.9",
"web3-core": "^1.2.11",
"web3-eth-contract": "^1.2.11",
"web3-utils": "^1.2.11"
},
"devDependencies": {
"@testing-library/jest-dom": "5.11.1",
"@testing-library/jest-dom": "5.11.2",
"@testing-library/react": "10.4.7",
"@testing-library/user-event": "12.0.13",
"@testing-library/user-event": "12.0.17",
"@typechain/web3-v1": "^1.0.0",
"@types/history": "4.6.2",
"@types/jest": "^26.0.7",
"@types/lodash.memoize": "^4.1.6",
"@types/node": "14.0.25",
"@types/node": "14.0.27",
"@types/react": "^16.9.43",
"@types/react-dom": "^16.9.8",
"@types/react-dom": "^16.9.6",
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.5",
"@types/styled-components": "^5.1.1",
"@typescript-eslint/eslint-plugin": "3.7.0",
"@typescript-eslint/parser": "3.7.0",
"@typescript-eslint/eslint-plugin": "3.7.1",
"@typescript-eslint/parser": "3.7.1",
"autoprefixer": "9.8.5",
"cross-env": "^7.0.2",
"dotenv": "^8.2.0",
@ -247,7 +254,7 @@
"eslint-plugin-import": "2.22.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react": "^7.20.5",
"eslint-plugin-sort-destructure-keys": "1.3.5",
"ethereumjs-abi": "0.6.8",
"husky": "^4.2.5",
@ -255,11 +262,9 @@
"node-sass": "^4.14.1",
"prettier": "2.0.5",
"react-app-rewired": "^2.1.6",
"source-map-explorer": "^2.4.2",
"truffle": "5.1.35",
"typescript": "^3.9.7",
"wait-on": "5.1.0",
"web3-eth-contract": "^1.2.11",
"web3-utils": "^1.2.11"
"truffle": "5.1.36",
"typechain": "^2.0.0",
"typescript": "3.9.7",
"wait-on": "5.1.0"
}
}

View File

@ -20,7 +20,25 @@ const secondButtonStyle = {
fontWeight: boldFont,
}
const Controls = ({ buttonLabels, currentStep, disabled, firstPage, lastPage, onPrevious, penultimate }) => {
interface Props {
buttonLabels?: string[]
currentStep: number
disabled: boolean
firstPage: boolean
lastPage: boolean
penultimate: boolean
onPrevious: () => void
}
const Controls = ({
buttonLabels,
currentStep,
disabled,
firstPage,
lastPage,
onPrevious,
penultimate,
}: Props): React.ReactElement => {
const back = firstPage ? 'Cancel' : 'Back'
let next
@ -28,7 +46,6 @@ const Controls = ({ buttonLabels, currentStep, disabled, firstPage, lastPage, on
// eslint-disable-next-line
next = firstPage ? 'Start' : penultimate ? 'Review' : lastPage ? 'Submit' : 'Next'
} else {
// $FlowFixMe
next = buttonLabels[currentStep]
}

View File

@ -1,11 +1,11 @@
import Paper from '@material-ui/core/Paper'
import { withStyles } from '@material-ui/core/styles'
import { makeStyles } from '@material-ui/core/styles'
import * as React from 'react'
import Block from 'src/components/layout/Block'
import { lg } from 'src/theme/variables'
const styles = () => ({
const useStyles = makeStyles({
root: {
margin: '10px',
maxWidth: '770px',
@ -16,11 +16,20 @@ const styles = () => ({
},
})
const OpenPaper = ({ children, classes, controls, padding = true }) => (
<Paper className={classes.root} elevation={1}>
<Block className={padding ? classes.padding : ''}>{children}</Block>
{controls}
</Paper>
)
interface Props {
padding?: boolean
controls: React.ReactNode
}
export default withStyles(styles as any)(OpenPaper)
const OpenPaper: React.FC<Props> = ({ children, controls, padding = true }) => {
const classes = useStyles()
return (
<Paper className={classes.root} elevation={1}>
<Block className={padding ? classes.padding : ''}>{children}</Block>
{controls}
</Paper>
)
}
export default OpenPaper

View File

@ -1,5 +0,0 @@
import * as React from 'react'
const Step = ({ children }) => <div>{children}</div>
export default Step

View File

@ -2,8 +2,9 @@ import FormStep from '@material-ui/core/Step'
import StepContent from '@material-ui/core/StepContent'
import StepLabel from '@material-ui/core/StepLabel'
import Stepper from '@material-ui/core/Stepper'
import { withStyles } from '@material-ui/core/styles'
import * as React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import React, { useCallback, useEffect, useState } from 'react'
import { FormApi } from 'final-form'
import Controls from './Controls'
@ -11,10 +12,6 @@ import GnoForm from 'src/components/forms/GnoForm'
import Hairline from 'src/components/layout/Hairline'
import { history } from 'src/store'
const { useEffect, useState } = React
export { default as Step } from './Step'
const transitionProps = {
timeout: {
enter: 350,
@ -22,11 +19,47 @@ const transitionProps = {
},
}
export const StepperPage = ({ children }: any) => children
export interface StepperPageFormProps {
values: Record<string, string>
errors: Record<string, string>
form: FormApi
}
const GnoStepper = (props: any) => {
interface StepperPageProps {
validate?: (...args: unknown[]) => undefined | string[] | Promise<undefined | Record<string, string>>
component: (
...args: unknown[]
) => (controls: React.ReactElement, formProps: StepperPageFormProps) => React.ReactElement
[key: string]: unknown
}
// TODO: Remove this magic
/* eslint-disable */
// @ts-ignore
export const StepperPage = ({}: StepperPageProps): null => null
/* eslint-enable */
type StepperFormValues = Record<string, string>
interface Mutators {
[key: string]: (...args: unknown[]) => void
}
interface GnoStepperProps<V = StepperFormValues> {
initialValues?: Partial<V>
onSubmit: (formValues: V) => void
steps: string[]
buttonLabels?: string[]
children: React.ReactNode
disabledWhenValidating?: boolean
mutators?: Mutators
testId?: string
}
function GnoStepper<V>(props: GnoStepperProps<V>): React.ReactElement {
const [page, setPage] = useState(0)
const [values, setValues] = useState({})
const classes = useStyles()
useEffect(() => {
if (props.initialValues) {
@ -39,15 +72,15 @@ const GnoStepper = (props: any) => {
return aux.props
}
const updateInitialProps = (newInitialProps) => {
const updateInitialProps = useCallback((newInitialProps) => {
setValues(newInitialProps)
}
}, [])
const getActivePageFrom = (pages) => {
const activePageProps = getPageProps(pages)
const { children, ...restProps } = activePageProps
const { component, ...restProps } = activePageProps
return children({ ...restProps, updateInitialProps })
return component({ ...restProps, updateInitialProps })
}
const validate = (valuesToValidate) => {
@ -92,12 +125,12 @@ const GnoStepper = (props: any) => {
return next(formValues)
}
const isLastPage = (pageNumber) => {
const isLastPage = (pageNumber: number): boolean => {
const { steps } = props
return pageNumber === steps.length - 1
}
const { buttonLabels, children, classes, disabledWhenValidating = false, mutators, steps, testId } = props
const { buttonLabels, children, disabledWhenValidating = false, mutators, steps, testId } = props
const activePage = getActivePageFrom(children)
const lastPage = isLastPage(page)
@ -157,7 +190,7 @@ const GnoStepper = (props: any) => {
)
}
const styles = {
const useStyles = makeStyles({
root: {
flex: '1 1 auto',
backgroundColor: 'transparent',
@ -170,6 +203,6 @@ const styles = {
cursor: 'pointer',
},
},
}
})
export default withStyles(styles as any)(GnoStepper)
export default GnoStepper

View File

@ -1,4 +1,4 @@
import { Record } from 'immutable'
import { Record, RecordOf } from 'immutable'
export interface AddressBookEntryProps {
address: string
@ -6,6 +6,8 @@ export interface AddressBookEntryProps {
isOwner: boolean
}
export type AddressBookEntryRecord = RecordOf<AddressBookEntryProps>
export const makeAddressBookEntry = Record<AddressBookEntryProps>({
address: '',
name: '',

View File

@ -121,5 +121,7 @@ export default handleActions(
})
},
},
Map(),
Map({
addressBook: Map({}),
}),
)

View File

@ -0,0 +1,24 @@
import { AddressBookEntryRecord, AddressBookEntryProps } from 'src/logic/addressBook/model/addressBook'
import { Map, List } from 'immutable'
export interface AddressBookReducerState {
addressBook: AddressBookMap
}
interface AddressBookMapSerialized {
[key: string]: AddressBookEntryProps
}
interface AddressBookReducerStateSerialized extends AddressBookReducerState {
addressBook: Record<string, AddressBookEntryProps[]>
}
export interface AddressBookMap extends Map<string> {
toJS(): AddressBookMapSerialized
get(key: string): List<AddressBookEntryRecord>
}
export interface AddressBookReducerMap extends Map<string, any> {
toJS(): AddressBookReducerStateSerialized
get<K extends keyof AddressBookReducerState>(key: K): AddressBookReducerState[K]
}

View File

@ -1,37 +1,28 @@
import { List, Map } from 'immutable'
import { AppReduxState } from 'src/store'
import { List } from 'immutable'
import { createSelector } from 'reselect'
import { ADDRESS_BOOK_REDUCER_ID } from 'src/logic/addressBook/store/reducer/addressBook'
import { AddressBookMap } from 'src/logic/addressBook/store/reducer/types/addressBook.d'
import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors'
export const addressBookMapSelector = (state) => state[ADDRESS_BOOK_REDUCER_ID].get('addressBook')
export const addressBookMapSelector = (state: AppReduxState): AddressBookMap =>
state[ADDRESS_BOOK_REDUCER_ID].get('addressBook')
export const getAddressBook = createSelector(
addressBookMapSelector,
safeParamAddressFromStateSelector,
(addressBook, safeAddress) => {
let result = Map([])
if (addressBook) {
result = addressBook.get(safeAddress, List([]))
}
return result
},
)
export const getAddressBookListSelector = createSelector(
addressBookMapSelector,
safeParamAddressFromStateSelector,
(addressBook, safeAddress) => {
let result = List([])
if (addressBook) {
result = List(addressBook.get(safeAddress))
result = addressBook.get(safeAddress)
}
return result
},
)
export const getNameFromAddressBook = createSelector(
getAddressBookListSelector,
getAddressBook,
(_, address) => address,
(addressBook, address) => {
const adbkEntry = addressBook.find((addressBookItem) => addressBookItem.address === address)

View File

@ -1,4 +1,6 @@
import { AbiItem } from 'web3-utils'
import contract from 'truffle-contract'
import Web3 from 'web3'
import ProxyFactorySol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxyFactory.json'
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafeProxy.json'
@ -8,7 +10,8 @@ import { getWeb3, getNetworkIdFrom } from 'src/logic/wallets/getWeb3'
import { calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { isProxyCode } from 'src/logic/contracts/historicProxyCode'
import Web3 from 'web3'
import { GnosisSafeProxyFactory } from 'src/types/contracts/GnosisSafeProxyFactory.d';
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001'
export const MULTI_SEND_ADDRESS = '0x8d29be29923b68abfdd21e541b9374737b49cdad'
@ -20,16 +23,16 @@ export const SAFE_MASTER_COPY_ADDRESS_V10 = '0xb6029EA3B2c51D09a50B53CA8012FeEB0
let proxyFactoryMaster
let safeMaster
const createGnosisSafeContract = (web3: Web3): any => {
const createGnosisSafeContract = (web3: Web3) => {
const gnosisSafe = contract(GnosisSafeSol)
gnosisSafe.setProvider(web3.currentProvider)
return gnosisSafe
}
const createProxyFactoryContract = (web3, networkId) => {
const createProxyFactoryContract = (web3: Web3, networkId: number): GnosisSafeProxyFactory => {
const contractAddress = ProxyFactorySol.networks[networkId].address
const proxyFactory = new web3.eth.Contract(ProxyFactorySol.abi as any, contractAddress)
const proxyFactory = new web3.eth.Contract(ProxyFactorySol.abi as AbiItem[], contractAddress) as unknown as GnosisSafeProxyFactory
return proxyFactory
}
@ -55,8 +58,8 @@ const createMasterCopies = async () => {
const accounts = await web3.eth.getAccounts()
const userAccount = accounts[0]
const ProxyFactory = getCreateProxyFactoryContract(web3, 4447)
proxyFactoryMaster = await ProxyFactory.new({ from: userAccount, gas: '5000000' })
const ProxyFactory = getCreateProxyFactoryContract(web3, 4441)
proxyFactoryMaster = await ProxyFactory.deploy({ data: GnosisSafeSol.bytecode }).send({ from: userAccount, gas: 5000000 })
const GnosisSafe = getGnosisSafeContract(web3)
safeMaster = await GnosisSafe.new({ from: userAccount, gas: '7000000' })
@ -70,7 +73,7 @@ export const getSafeMasterContract = async () => {
return safeMaster
}
export const getSafeDeploymentTransaction = (safeAccounts, numConfirmations, userAccount) => {
export const getSafeDeploymentTransaction = (safeAccounts, numConfirmations) => {
const gnosisSafeData = safeMaster.contract.methods
.setup(safeAccounts, numConfirmations, ZERO_ADDRESS, '0x', DEFAULT_FALLBACK_HANDLER_ADDRESS, ZERO_ADDRESS, 0, ZERO_ADDRESS)
.encodeABI()
@ -95,11 +98,12 @@ export const estimateGasForDeployingSafe = async (
return gas * parseInt(gasPrice, 10)
}
export const getGnosisSafeInstanceAt = memoize(async (safeAddress: string): Promise<any> => {
export const getGnosisSafeInstanceAt = async (safeAddress: string): Promise<GnosisSafe> => {
const web3 = getWeb3()
const GnosisSafe = await getGnosisSafeContract(web3)
return GnosisSafe.at(safeAddress)
})
const gnosisSafe = await new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown as GnosisSafe
return gnosisSafe
}
const cleanByteCodeMetadata = (bytecode: string): string => {
const metaData = 'a165'
@ -124,39 +128,3 @@ export const validateProxy = async (safeAddress: string): Promise<boolean> => {
return isProxyCode(codeWithoutMetadata)
}
export const getEncodedMultiSendCallData = (txs, web3) => {
const multiSendAbi = [
{
type: 'function',
name: 'multiSend',
constant: false,
payable: false,
stateMutability: 'nonpayable',
inputs: [{ type: 'bytes', name: 'transactions' }],
outputs: [],
},
]
const multiSend = new web3.eth.Contract(multiSendAbi, MULTI_SEND_ADDRESS)
const encodeMultiSendCallData = multiSend.methods
.multiSend(
`0x${txs
.map((tx) => [
web3.eth.abi.encodeParameter('uint8', 0).slice(-2),
web3.eth.abi.encodeParameter('address', tx.to).slice(-40),
web3.eth.abi.encodeParameter('uint256', tx.value).slice(-64),
web3.eth.abi
.encodeParameter(
'uint256',
web3.utils.hexToBytes(tx.data).length,
)
.slice(-64),
tx.data.replace(/^0x/, ''),
].join(''))
.join('')}`,
)
.encodeABI()
return encodeMultiSendCallData
}

View File

@ -1,15 +1,18 @@
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { BigNumber } from 'bignumber.js'
import { AbiItem } from 'web3-utils'
import { CALL } from '.'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { generateSignaturesFromTxConfirmations } from 'src/logic/safe/safeTxSigner'
import { Transaction } from 'src/routes/safe/store/models/types/transaction'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { EMPTY_DATA, calculateGasOf, calculateGasPrice } from 'src/logic/wallets/ethTransactions'
import { getAccountFrom, getWeb3 } from 'src/logic/wallets/getWeb3'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
const estimateDataGasCosts = (data) => {
const estimateDataGasCosts = (data: string): number => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0
@ -25,33 +28,37 @@ const estimateDataGasCosts = (data) => {
return data.match(/.{2}/g).reduce(reducer, 0)
}
export const estimateTxGasCosts = async (safeAddress, to, data, tx?: any, preApprovingOwner?: any) => {
export const estimateTxGasCosts = async (
safeAddress: string,
to: string,
data: string,
tx?: Transaction,
preApprovingOwner?: string,
): Promise<number> => {
try {
const web3 = getWeb3()
const from = await getAccountFrom(web3)
const safeInstance: any = new web3.eth.Contract(GnosisSafeSol.abi as any, safeAddress)
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[], safeAddress) as unknown) as GnosisSafe
const nonce = await safeInstance.methods.nonce().call()
const threshold = await safeInstance.methods.getThreshold().call()
const isExecution = (tx && tx.confirmations.size === threshold) || !!preApprovingOwner || threshold === '1'
const isExecution = tx?.confirmations.size === Number(threshold) || !!preApprovingOwner || threshold === '1'
let txData
if (isExecution) {
// https://docs.gnosis.io/safe/docs/docs5/#pre-validated-signatures
const signatures =
tx && tx.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
const signatures = tx?.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
txData = await safeInstance.methods
.execTransaction(
to,
tx ? tx.value : 0,
tx?.value || 0,
data,
CALL,
tx ? tx.safeTxGas : 0,
tx?.safeTxGas || 0,
0,
0,
ZERO_ADDRESS,
@ -61,7 +68,7 @@ export const estimateTxGasCosts = async (safeAddress, to, data, tx?: any, preApp
.encodeABI()
} else {
const txHash = await safeInstance.methods
.getTransactionHash(to, tx ? tx.value : 0, data, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, nonce)
.getTransactionHash(to, tx?.value || 0, data, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, nonce)
.call({
from,
})
@ -80,16 +87,23 @@ export const estimateTxGasCosts = async (safeAddress, to, data, tx?: any, preApp
}
}
export const estimateSafeTxGas = async (safe, safeAddress, data, to, valueInWei, operation) => {
export const estimateSafeTxGas = async (
safe: GnosisSafe | undefined,
safeAddress: string,
data: string,
to: string,
valueInWei: string,
operation: number,
): Promise<number> => {
try {
let safeInstance = safe
if (!safeInstance) {
safeInstance = await getGnosisSafeInstanceAt(safeAddress)
}
const web3: any = await getWeb3()
const estimateData = safeInstance.contract.methods.requiredTxGas(to, valueInWei, data, operation).encodeABI()
const estimateResponse: any = await web3.eth.call({
const web3 = await getWeb3()
const estimateData = safeInstance.methods.requiredTxGas(to, valueInWei, data, operation).encodeABI()
const estimateResponse = await web3.eth.call({
to: safeAddress,
from: safeAddress,
data: estimateData,
@ -98,17 +112,20 @@ export const estimateSafeTxGas = async (safe, safeAddress, data, to, valueInWei,
// 21000 - additional gas costs (e.g. base tx costs, transfer costs)
const dataGasEstimation = estimateDataGasCosts(estimateData) + 21000
const additionalGasBatches = [10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000]
const batch = new web3.BatchRequest()
const estimationRequests = additionalGasBatches.map(
(additionalGas) =>
new Promise((resolve) => {
// there are no type definitions for .request, so for now ts-ignore is there
// Issue link: https://github.com/ethereum/web3.js/issues/3144
// eslint-disable-next-line
// @ts-ignore
const request = web3.eth.call.request(
{
to: safe.address,
from: safe.address,
to: safeAddress,
from: safeAddress,
data: estimateData,
gasPrice: 0,
gasLimit: txGasEstimation + dataGasEstimation + additionalGas,

View File

@ -1,6 +1,4 @@
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { NonPayableTransactionObject } from 'src/types/contracts/types.d'
import { TxArgs } from 'src/routes/safe/store/models/types/transaction'
export const CALL = 0
@ -21,36 +19,22 @@ export const getApprovalTransaction = async ({
sender,
to,
valueInWei,
}: TxArgs) => {
const txHash = await safeInstance.getTransactionHash(
to,
valueInWei,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce,
{
}: TxArgs): Promise<NonPayableTransactionObject<void>> => {
const txHash = await safeInstance.methods
.getTransactionHash(to, valueInWei, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, nonce)
.call({
from: sender,
},
)
})
try {
const web3 = getWeb3()
const contract: any = new web3.eth.Contract(GnosisSafeSol.abi as any, safeInstance.address)
return contract.methods.approveHash(txHash)
return safeInstance.methods.approveHash(txHash)
} catch (err) {
console.error(`Error while approving transaction: ${err}`)
throw err
}
}
export const getExecutionTransaction = async ({
export const getExecutionTransaction = ({
baseGas,
data,
gasPrice,
@ -62,12 +46,9 @@ export const getExecutionTransaction = async ({
sigs,
to,
valueInWei,
}: TxArgs) => {
}: TxArgs): NonPayableTransactionObject<boolean> => {
try {
const web3 = getWeb3()
const contract: any = new web3.eth.Contract(GnosisSafeSol.abi as any, safeInstance.address)
return contract.methods.execTransaction(
return safeInstance.methods.execTransaction(
to,
valueInWei,
data,

View File

@ -1,10 +1,11 @@
import axios from 'axios'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
import { getTxServiceHost, getTxServiceUriFrom } from 'src/config'
import { checksumAddress } from 'src/utils/checksumAddress'
const calculateBodyFrom = async (
safeInstance,
safeInstance: GnosisSafe,
to,
valueInWei,
data,
@ -20,18 +21,9 @@ const calculateBodyFrom = async (
origin,
signature,
) => {
const contractTransactionHash = await safeInstance.getTransactionHash(
to,
valueInWei,
data,
operation,
safeTxGas,
baseGas,
gasPrice,
gasToken,
refundReceiver,
nonce,
)
const contractTransactionHash = await safeInstance.methods
.getTransactionHash(to, valueInWei, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, nonce)
.call()
return {
to: checksumAddress(to),
@ -52,7 +44,7 @@ const calculateBodyFrom = async (
}
}
export const buildTxServiceUrl = (safeAddress) => {
export const buildTxServiceUrl = (safeAddress: string): string => {
const host = getTxServiceHost()
const address = checksumAddress(safeAddress)
const base = getTxServiceUriFrom(address)
@ -61,6 +53,11 @@ export const buildTxServiceUrl = (safeAddress) => {
const SUCCESS_STATUS = 201 // CREATED status
interface SaveTxToHistoryArgs {
safeInstance: GnosisSafe
[key: string]: any
}
export const saveTxToHistory = async ({
baseGas,
data,
@ -77,8 +74,8 @@ export const saveTxToHistory = async ({
to,
txHash,
valueInWei,
}: any) => {
const url = buildTxServiceUrl(safeInstance.address)
}: SaveTxToHistoryArgs): Promise<void> => {
const url = buildTxServiceUrl(safeInstance.options.address)
const body = await calculateBodyFrom(
safeInstance,
to,

View File

@ -1,30 +1,36 @@
//
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
import { AbiItem } from 'web3-utils'
import Web3 from 'web3'
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { checkIfSafeNeedsUpdate } from 'src/logic/safe/utils/safeVersion'
describe('Check safe version', () => {
it('Calls checkIfSafeNeedUpdate, should return true if the safe version is bellow the target one', async () => {
const web3 = new Web3(new Web3.providers.HttpProvider(''))
const safeInstance: any = new web3.eth.Contract(GnosisSafeSol.abi as any)
safeInstance.VERSION = () => '1.0.0'
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[]) as unknown) as GnosisSafe
// eslint-disable-next-line
// @ts-ignore
safeInstance.methods.VERSION = () => ({ call: async () => '1.0.0' })
const targetVersion = '1.1.1'
const { needUpdate } = await checkIfSafeNeedsUpdate(safeInstance, targetVersion)
expect(needUpdate).toEqual(true)
})
it('Calls checkIfSafeNeedUpdate, should return false if the safe version is over the target one', async () => {
const web3 = new Web3(new Web3.providers.HttpProvider(''))
const safeInstance: any = new web3.eth.Contract(GnosisSafeSol.abi as any)
safeInstance.VERSION = () => '2.0.0'
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[]) as unknown) as GnosisSafe
// eslint-disable-next-line
// @ts-ignore
safeInstance.methods.VERSION = () => ({ call: async () => '2.0.0' })
const targetVersion = '1.1.1'
const { needUpdate } = await checkIfSafeNeedsUpdate(safeInstance, targetVersion)
expect(needUpdate).toEqual(false)
})
it('Calls checkIfSafeNeedUpdate, should return false if the safe version is equal the target one', async () => {
const web3 = new Web3(new Web3.providers.HttpProvider(''))
const safeInstance: any = new web3.eth.Contract(GnosisSafeSol.abi as any)
safeInstance.VERSION = () => '1.1.1'
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[]) as unknown) as GnosisSafe
// eslint-disable-next-line
// @ts-ignore
safeInstance.methods.VERSION = () => ({ call: async () => '1.1.1' })
const targetVersion = '1.1.1'
const { needUpdate } = await checkIfSafeNeedsUpdate(safeInstance, targetVersion)
expect(needUpdate).toEqual(false)

View File

@ -1,6 +1,7 @@
import semverLessThan from 'semver/functions/lt'
import semverSatisfies from 'semver/functions/satisfies'
import semverValid from 'semver/functions/valid'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
import { getSafeLastVersion } from 'src/config'
import { getGnosisSafeInstanceAt, getSafeMasterContract } from 'src/logic/contracts/safeContracts'
@ -21,10 +22,10 @@ export const safeNeedsUpdate = (currentVersion: string, latestVersion: string):
return latest ? semverLessThan(current, latest) : false
}
export const getCurrentSafeVersion = (gnosisSafeInstance: { VERSION: () => Promise<string> }): Promise<string> =>
gnosisSafeInstance.VERSION()
export const getCurrentSafeVersion = (gnosisSafeInstance: GnosisSafe): Promise<string> =>
gnosisSafeInstance.methods.VERSION().call()
export const enabledFeatures = (version: string): Array<string> =>
export const enabledFeatures = (version: string): string[] =>
FEATURES.reduce((acc, feature) => {
if (semverSatisfies(version, feature.validVersion)) {
acc.push(feature.name)
@ -39,7 +40,7 @@ interface SafeVersionInfo {
}
export const checkIfSafeNeedsUpdate = async (
gnosisSafeInstance: { VERSION: () => Promise<string> },
gnosisSafeInstance: GnosisSafe,
lastSafeVersion: string,
): Promise<SafeVersionInfo> => {
if (!gnosisSafeInstance || !lastSafeVersion) {

View File

@ -1,19 +1,16 @@
//
import { AbiItem } from 'web3-utils'
import Web3 from 'web3'
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import {
DEFAULT_FALLBACK_HANDLER_ADDRESS,
getEncodedMultiSendCallData,
SAFE_MASTER_COPY_ADDRESS,
} from 'src/logic/contracts/safeContracts'
import { DEFAULT_FALLBACK_HANDLER_ADDRESS, SAFE_MASTER_COPY_ADDRESS } from 'src/logic/contracts/safeContracts'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { getEncodedMultiSendCallData } from 'src/logic/safe/utils/upgradeSafe'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
describe('Upgrade a Safe', () => {
it('Calls getEncodedMultiSendCallData with a list of MultiSendTransactionInstanceType and returns the multiSend data encoded', async () => {
const safeAddress = ZERO_ADDRESS
const web3 = new Web3(new Web3.providers.HttpProvider(''))
const safeInstance = new web3.eth.Contract(GnosisSafeSol.abi as any)
const safeInstance = (new web3.eth.Contract(GnosisSafeSol.abi as AbiItem[]) as unknown) as GnosisSafe
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
const txs = [
@ -30,7 +27,8 @@ describe('Upgrade a Safe', () => {
data: fallbackHandlerTxData,
},
]
const expectedEncodedData = '0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247de7edef00000000000000000000000034cfac646f301356faa8b21e94227e3583fe3f5f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f08a0323000000000000000000000000d5d82b6addc9027b22dca772aa68d5d74cdbdf440000000000000000000000000000'
const expectedEncodedData =
'0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247de7edef00000000000000000000000034cfac646f301356faa8b21e94227e3583fe3f5f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024f08a0323000000000000000000000000d5d82b6addc9027b22dca772aa68d5d74cdbdf440000000000000000000000000000'
const multiSendTxData = getEncodedMultiSendCallData(txs, web3)
expect(multiSendTxData).toEqual(expectedEncodedData)
})

View File

@ -1,33 +1,58 @@
import Web3 from 'web3'
import { AbiItem } from 'web3-utils'
import {
DEFAULT_FALLBACK_HANDLER_ADDRESS,
MULTI_SEND_ADDRESS,
SAFE_MASTER_COPY_ADDRESS,
getEncodedMultiSendCallData,
getGnosisSafeInstanceAt,
} from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { MultiSend } from 'src/types/contracts/MultiSend.d'
export const upgradeSafeToLatestVersion = async (safeAddress, createTransaction) => {
const sendTransactions = async (txs) => {
const web3 = getWeb3()
const encodeMultiSendCallData = getEncodedMultiSendCallData(txs, web3)
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: '0',
txData: encodeMultiSendCallData,
notifiedTransaction: 'STANDARD_TX',
enqueueSnackbar: () => {},
closeSnackbar: () => {},
operation: DELEGATE_CALL,
})
}
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const fallbackHandlerTxData = safeInstance.contract.methods
.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS)
interface MultiSendTx {
operation: number
to: string
value: number
data: string
}
export const getEncodedMultiSendCallData = (txs: MultiSendTx[], web3: Web3): string => {
const multiSendAbi: AbiItem[] = [
{
type: 'function',
name: 'multiSend',
constant: false,
payable: false,
stateMutability: 'nonpayable',
inputs: [{ type: 'bytes', name: 'transactions' }],
outputs: [],
},
]
const multiSend = (new web3.eth.Contract(multiSendAbi, MULTI_SEND_ADDRESS) as unknown) as MultiSend
const encodedMultiSendCallData = multiSend.methods
.multiSend(
`0x${txs
.map((tx) =>
[
web3.eth.abi.encodeParameter('uint8', 0).slice(-2),
web3.eth.abi.encodeParameter('address', tx.to).slice(-40),
web3.eth.abi.encodeParameter('uint256', tx.value).slice(-64),
web3.eth.abi.encodeParameter('uint256', web3.utils.hexToBytes(tx.data).length).slice(-64),
tx.data.replace(/^0x/, ''),
].join(''),
)
.join('')}`,
)
.encodeABI()
const updateSafeTxData = safeInstance.contract.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
return encodedMultiSendCallData
}
export const upgradeSafeToLatestVersion = async (safeAddress: string, createTransaction): Promise<void> => {
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
const txs = [
{
operation: 0,
@ -42,5 +67,19 @@ export const upgradeSafeToLatestVersion = async (safeAddress, createTransaction)
data: fallbackHandlerTxData,
},
]
return sendTransactions(txs)
const web3 = getWeb3()
const encodeMultiSendCallData = getEncodedMultiSendCallData(txs, web3)
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: 0,
txData: encodeMultiSendCallData,
notifiedTransaction: 'STANDARD_TX',
enqueueSnackbar: () => {},
closeSnackbar: () => {},
operation: DELEGATE_CALL,
})
return
}

View File

@ -1,10 +1,12 @@
import InputAdornment from '@material-ui/core/InputAdornment'
import { withStyles } from '@material-ui/core/styles'
import { makeStyles } from '@material-ui/core/styles'
import CheckCircle from '@material-ui/icons/CheckCircle'
import * as React from 'react'
import { FormApi } from 'final-form'
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
import OpenPaper from 'src/components/Stepper/OpenPaper'
import { StepperPageFormProps } from 'src/components/Stepper'
import AddressInput from 'src/components/forms/AddressInput'
import Field from 'src/components/forms/Field'
import TextField from 'src/components/forms/TextField'
@ -17,7 +19,7 @@ import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME } from 'src/routes/load/components/fields'
import { secondary } from 'src/theme/variables'
const styles = () => ({
const useStyles = makeStyles({
root: {
display: 'flex',
maxWidth: '460px',
@ -40,7 +42,7 @@ export const SAFE_MASTERCOPY_ERROR = 'Mastercopy used by this Safe is not the sa
// In case of an error here, it will be swallowed by final-form
// So if you're experiencing any strang behaviours like freeze or hanging
// Don't mind to check if everything is OK inside this function :)
export const safeFieldsValidation = async (values) => {
export const safeFieldsValidation = async (values): Promise<Record<string, string>> => {
const errors = {}
const web3 = getWeb3()
const safeAddress = values[FIELD_LOAD_ADDRESS]
@ -75,11 +77,19 @@ export const safeFieldsValidation = async (values) => {
return errors
}
const Details = ({ classes, errors, form }) => {
const handleScan = (value, closeQrModal) => {
interface DetailsFormProps {
errors: Record<string, string>
form: FormApi
}
const DetailsForm = ({ errors, form }: DetailsFormProps): React.ReactElement => {
const classes = useStyles()
const handleScan = (value: string, closeQrModal: () => void): void => {
form.mutators.setValue(FIELD_LOAD_ADDRESS, value)
closeQrModal()
}
return (
<>
<Block margin="md">
@ -146,9 +156,7 @@ const Details = ({ classes, errors, form }) => {
)
}
const DetailsForm = withStyles(styles as any)(Details)
const DetailsPage = () => (controls, { errors, form }) => (
const DetailsPage = () => (controls: React.ReactNode, { errors, form }: StepperPageFormProps): React.ReactElement => (
<>
<OpenPaper controls={controls}>
<DetailsForm errors={errors} form={form} />

View File

@ -14,7 +14,8 @@ import { history } from 'src/store'
import { secondary, sm } from 'src/theme/variables'
import { LoadFormValues } from '../container/Load'
const getSteps = () => ['Name and address', 'Owners', 'Review']
const steps = ['Name and address', 'Owners', 'Review']
const buttonLabels = ['Next', 'Review', 'Load']
const iconStyle = {
color: secondary,
@ -32,49 +33,39 @@ const formMutators = {
},
}
const buttonLabels = ['Next', 'Review', 'Load']
interface ILayout {
interface LayoutProps {
network: string
provider?: string
userAddress: string
onLoadSafeSubmit: (values: LoadFormValues) => void
}
const Layout: React.FC<ILayout> = ({ network, onLoadSafeSubmit, provider, userAddress }) => {
const steps = getSteps()
const initialValues = {}
return (
<>
{provider ? (
<Block>
<Row align="center">
<IconButton disableRipple onClick={back} style={iconStyle}>
<ChevronLeft />
</IconButton>
<Heading tag="h2">Load existing Safe</Heading>
</Row>
<Stepper
buttonLabels={buttonLabels}
initialValues={initialValues}
mutators={formMutators}
onSubmit={onLoadSafeSubmit}
steps={steps}
testId="load-safe-form"
>
<StepperPage validate={safeFieldsValidation}>{DetailsForm}</StepperPage>
<StepperPage network={network}>{OwnerList}</StepperPage>
<StepperPage network={network} userAddress={userAddress}>
{ReviewInformation}
</StepperPage>
</Stepper>
</Block>
) : (
<div>No account detected</div>
)}
</>
)
}
const Layout = ({ network, onLoadSafeSubmit, provider, userAddress }: LayoutProps): React.ReactElement => (
<>
{provider ? (
<Block>
<Row align="center">
<IconButton disableRipple onClick={back} style={iconStyle}>
<ChevronLeft />
</IconButton>
<Heading tag="h2">Load existing Safe</Heading>
</Row>
<Stepper<LoadFormValues>
buttonLabels={buttonLabels}
mutators={formMutators}
onSubmit={onLoadSafeSubmit}
steps={steps}
testId="load-safe-form"
>
<StepperPage validate={safeFieldsValidation} component={DetailsForm} />
<StepperPage network={network} component={OwnerList} />
<StepperPage network={network} userAddress={userAddress} component={ReviewInformation} />
</Stepper>
</Block>
) : (
<div>No account detected</div>
)}
</>
)
export default Layout

View File

@ -88,11 +88,11 @@ const OwnerListComponent = (props) => {
const fetchSafe = async () => {
const safeAddress = values[FIELD_LOAD_ADDRESS]
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const safeOwners = await gnosisSafe.getOwners()
const threshold = await gnosisSafe.getThreshold()
const safeOwners = await gnosisSafe.methods.getOwners().call()
const threshold = await gnosisSafe.methods.getThreshold().call()
if (isCurrent && owners) {
const sortedOwners = safeOwners.sort()
if (isCurrent) {
const sortedOwners = safeOwners.slice().sort()
const initialValues = calculateSafeValues(sortedOwners, threshold, values)
updateInitialProps(initialValues)
setOwners(sortedOwners)
@ -104,7 +104,7 @@ const OwnerListComponent = (props) => {
return () => {
isCurrent = false
}
}, [owners, updateInitialProps, values])
}, [updateInitialProps, values])
return (
<>

View File

@ -1,7 +1,6 @@
import TableContainer from '@material-ui/core/TableContainer'
import { withStyles } from '@material-ui/core/styles'
import classNames from 'classnames'
import * as React from 'react'
import React from 'react'
import CopyBtn from 'src/components/CopyBtn'
import EtherscanBtn from 'src/components/EtherscanBtn'
@ -16,73 +15,9 @@ import { shortVersionOf } from 'src/logic/wallets/ethAddresses'
import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME, THRESHOLD } from 'src/routes/load/components/fields'
import { getNumOwnersFrom, getOwnerAddressBy, getOwnerNameBy } from 'src/routes/open/components/fields'
import { getAccountsFrom } from 'src/routes/open/utils/safeDataExtractor'
import { border, lg, screenSm, sm, xs } from 'src/theme/variables'
import { useStyles } from './styles'
const styles = () => ({
root: {
flexDirection: 'column',
minHeight: '300px',
[`@media (min-width: ${screenSm}px)`]: {
flexDirection: 'row',
},
},
detailsColumn: {
minWidth: '100%',
[`@media (min-width: ${screenSm}px)`]: {
minWidth: '0',
},
},
ownersColumn: {
minWidth: '100%',
[`@media (min-width: ${screenSm}px)`]: {
minWidth: '0',
},
},
details: {
padding: lg,
borderRight: `solid 1px ${border}`,
height: '100%',
},
owners: {
padding: lg,
},
name: {
textOverflow: 'ellipsis',
overflow: 'hidden',
},
userName: {
whiteSpace: 'nowrap',
},
owner: {
alignItems: 'center',
minWidth: 'fit-content',
padding: sm,
paddingLeft: lg,
},
user: {
justifyContent: 'left',
'& > p': {
marginRight: sm,
},
},
open: {
paddingLeft: sm,
width: 'auto',
'&:hover': {
cursor: 'pointer',
},
},
container: {
marginTop: xs,
alignItems: 'center',
},
address: {
paddingLeft: '6px',
marginRight: sm,
},
})
const checkUserAddressOwner = (values, userAddress) => {
const checkIfUserAddressIsAnOwner = (values: Record<string, string>, userAddress: string): boolean => {
let isOwner = false
for (let i = 0; i < getNumOwnersFrom(values); i += 1) {
@ -95,116 +30,119 @@ const checkUserAddressOwner = (values, userAddress) => {
return isOwner
}
class ReviewComponent extends React.PureComponent<any> {
render() {
const { classes, userAddress, values } = this.props
const isOwner = checkUserAddressOwner(values, userAddress)
const owners = getAccountsFrom(values)
const safeAddress = values[FIELD_LOAD_ADDRESS]
return (
<>
<Row className={classes.root}>
<Col className={classes.detailsColumn} layout="column" xs={4}>
<Block className={classes.details}>
<Block margin="lg">
<Paragraph color="primary" noMargin size="lg" data-testid="load-safe-step-three">
Review details
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Name of the Safe
</Paragraph>
<Paragraph
className={classes.name}
color="primary"
noMargin
size="lg"
weight="bolder"
data-testid="load-form-review-safe-name"
>
{values[FIELD_LOAD_NAME]}
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Safe address
</Paragraph>
<Row className={classes.container}>
<Identicon address={safeAddress} diameter={32} />
<Paragraph className={classes.address} color="disabled" noMargin size="md">
{shortVersionOf(safeAddress, 4)}
</Paragraph>
<CopyBtn content={safeAddress} />
<EtherscanBtn type="address" value={safeAddress} />
</Row>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Connected wallet client is owner?
</Paragraph>
<Paragraph className={classes.name} color="primary" noMargin size="lg" weight="bolder">
{isOwner ? 'Yes' : 'No (read-only)'}
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Any transaction requires the confirmation of:
</Paragraph>
<Paragraph className={classes.name} color="primary" noMargin size="lg" weight="bolder">
{`${values[THRESHOLD]} out of ${getNumOwnersFrom(values)} owners`}
</Paragraph>
</Block>
</Block>
</Col>
<Col className={classes.ownersColumn} layout="column" xs={8}>
<TableContainer>
<Block className={classes.owners}>
<Paragraph color="primary" noMargin size="lg">
{`${getNumOwnersFrom(values)} Safe owners`}
</Paragraph>
</Block>
<Hairline />
{owners.map((address, index) => (
<>
<Row className={classes.owner}>
<Col align="center" xs={1}>
<Identicon address={address} diameter={32} />
</Col>
<Col xs={11}>
<Block className={classNames(classes.name, classes.userName)}>
<Paragraph noMargin size="lg" data-testid="load-safe-review-owner-name">
{values[getOwnerNameBy(index)]}
</Paragraph>
<Block className={classes.user} justify="center">
<Paragraph color="disabled" noMargin size="md">
{address}
</Paragraph>
<CopyBtn content={address} />
<EtherscanBtn type="address" value={address} />
</Block>
</Block>
</Col>
</Row>
{index !== owners.length - 1 && <Hairline />}
</>
))}
</TableContainer>
</Col>
</Row>
</>
)
}
interface Props {
userAddress: string
values: Record<string, string>
}
const ReviewPage = withStyles(styles as any)(ReviewComponent)
const ReviewComponent = ({ userAddress, values }: Props): React.ReactElement => {
const classes = useStyles()
const isOwner = checkIfUserAddressIsAnOwner(values, userAddress)
const owners = getAccountsFrom(values)
const safeAddress = values[FIELD_LOAD_ADDRESS]
const Review = ({ network, userAddress }) => (controls, { values }) => (
return (
<>
<Row className={classes.root}>
<Col className={classes.detailsColumn} layout="column" xs={4}>
<Block className={classes.details}>
<Block margin="lg">
<Paragraph color="primary" noMargin size="lg" data-testid="load-safe-step-three">
Review details
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Name of the Safe
</Paragraph>
<Paragraph
className={classes.name}
color="primary"
noMargin
size="lg"
weight="bolder"
data-testid="load-form-review-safe-name"
>
{values[FIELD_LOAD_NAME]}
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Safe address
</Paragraph>
<Row className={classes.container}>
<Identicon address={safeAddress} diameter={32} />
<Paragraph className={classes.address} color="disabled" noMargin size="md">
{shortVersionOf(safeAddress, 4)}
</Paragraph>
<CopyBtn content={safeAddress} />
<EtherscanBtn type="address" value={safeAddress} />
</Row>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Connected wallet client is owner?
</Paragraph>
<Paragraph className={classes.name} color="primary" noMargin size="lg" weight="bolder">
{isOwner ? 'Yes' : 'No (read-only)'}
</Paragraph>
</Block>
<Block margin="lg">
<Paragraph color="disabled" noMargin size="sm">
Any transaction requires the confirmation of:
</Paragraph>
<Paragraph className={classes.name} color="primary" noMargin size="lg" weight="bolder">
{`${values[THRESHOLD]} out of ${getNumOwnersFrom(values)} owners`}
</Paragraph>
</Block>
</Block>
</Col>
<Col className={classes.ownersColumn} layout="column" xs={8}>
<TableContainer>
<Block className={classes.owners}>
<Paragraph color="primary" noMargin size="lg">
{`${getNumOwnersFrom(values)} Safe owners`}
</Paragraph>
</Block>
<Hairline />
{owners.map((address, index) => (
<>
<Row className={classes.owner}>
<Col align="center" xs={1}>
<Identicon address={address} diameter={32} />
</Col>
<Col xs={11}>
<Block className={classNames(classes.name, classes.userName)}>
<Paragraph noMargin size="lg" data-testid="load-safe-review-owner-name">
{values[getOwnerNameBy(index)]}
</Paragraph>
<Block className={classes.user} justify="center">
<Paragraph color="disabled" noMargin size="md">
{address}
</Paragraph>
<CopyBtn content={address} />
<EtherscanBtn type="address" value={address} />
</Block>
</Block>
</Col>
</Row>
{index !== owners.length - 1 && <Hairline />}
</>
))}
</TableContainer>
</Col>
</Row>
</>
)
}
const Review = ({ userAddress }: { userAddress: string }) => (
controls: React.ReactNode,
{ values }: { values: Record<string, string> },
): React.ReactElement => (
<>
<OpenPaper controls={controls} padding={false}>
<ReviewPage network={network} userAddress={userAddress} values={values} />
<ReviewComponent userAddress={userAddress} values={values} />
</OpenPaper>
</>
)

View File

@ -0,0 +1,66 @@
import { makeStyles } from '@material-ui/core/styles'
import { border, lg, screenSm, sm, xs } from 'src/theme/variables'
export const useStyles = makeStyles({
root: {
flexDirection: 'column',
minHeight: '300px',
[`@media (min-width: ${screenSm}px)`]: {
flexDirection: 'row',
},
},
detailsColumn: {
minWidth: '100%',
[`@media (min-width: ${screenSm}px)`]: {
minWidth: '0',
},
},
ownersColumn: {
minWidth: '100%',
[`@media (min-width: ${screenSm}px)`]: {
minWidth: '0',
},
},
details: {
padding: lg,
borderRight: `solid 1px ${border}`,
height: '100%',
},
owners: {
padding: lg,
},
name: {
textOverflow: 'ellipsis',
overflow: 'hidden',
},
userName: {
whiteSpace: 'nowrap',
},
owner: {
alignItems: 'center',
minWidth: 'fit-content',
padding: sm,
paddingLeft: lg,
},
user: {
justifyContent: 'left',
'& > p': {
marginRight: sm,
},
},
open: {
paddingLeft: sm,
width: 'auto',
'&:hover': {
cursor: 'pointer',
},
},
container: {
marginTop: xs,
alignItems: 'center',
},
address: {
paddingLeft: '6px',
marginRight: sm,
},
})

View File

@ -37,7 +37,7 @@ export const loadSafe = async (
await addSafe(safeProps)
}
interface ILoad {
interface LoadProps {
addSafe: Dispatch<any>
network: string
provider?: string
@ -50,7 +50,7 @@ export interface LoadFormValues {
threshold: string
}
const Load: React.FC<ILoad> = ({ addSafe, network, provider, userAddress }) => {
const Load = ({ addSafe, network, provider, userAddress }: LoadProps): React.ReactElement => {
const onLoadSafeSubmit = async (values: LoadFormValues) => {
let safeAddress = values[FIELD_LOAD_ADDRESS]
// TODO: review this check. It doesn't seems to be necessary at this point
@ -65,7 +65,7 @@ const Load: React.FC<ILoad> = ({ addSafe, network, provider, userAddress }) => {
const ownerNames = getNamesFrom(values)
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const ownerAddresses = await gnosisSafe.getOwners()
const ownerAddresses = await gnosisSafe.methods.getOwners().call()
const owners = getOwnersFrom(ownerNames, ownerAddresses.sort())
await loadSafe(safeName, safeAddress, owners, addSafe)

View File

@ -98,11 +98,9 @@ const Layout = (props) => {
steps={steps}
testId="create-safe-form"
>
<StepperPage>{SafeNameField}</StepperPage>
<StepperPage>{SafeOwnersFields}</StepperPage>
<StepperPage network={network} userAccount={userAccount}>
{Review}
</StepperPage>
<StepperPage component={SafeNameField} />
<StepperPage component={SafeOwnersFields} />
<StepperPage network={network} userAccount={userAccount} component={Review} />
</Stepper>
</Block>
) : (

View File

@ -59,9 +59,9 @@ export const createSafe = (values, userAccount) => {
const ownersNames = getNamesFrom(values)
const ownerAddresses = getAccountsFrom(values)
const deploymentTxMethod = getSafeDeploymentTransaction(ownerAddresses, confirmations, userAccount)
const deploymentTx = getSafeDeploymentTransaction(ownerAddresses, confirmations)
const promiEvent = deploymentTxMethod.send({ from: userAccount, value: 0 })
const promiEvent = deploymentTx.send({ from: userAccount, value: 0 })
promiEvent
.once('transactionHash', (txHash) => {

View File

@ -19,7 +19,7 @@ import Col from 'src/components/layout/Col'
import Hairline from 'src/components/layout/Hairline'
import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row'
import { getAddressBookListSelector } from 'src/logic/addressBook/store/selectors'
import { getAddressBook } from 'src/logic/addressBook/store/selectors'
import { getAddressesListFromAdbk } from 'src/logic/addressBook/utils'
export const CREATE_ENTRY_INPUT_NAME_ID = 'create-entry-input-name'
@ -42,7 +42,7 @@ const CreateEditEntryModalComponent = ({
}
}
const addressBook = useSelector(getAddressBookListSelector)
const addressBook = useSelector(getAddressBook)
const addressBookAddressesList = getAddressesListFromAdbk(addressBook)
const entryDoesntExist = uniqueAddress(addressBookAddressesList)

View File

@ -22,7 +22,7 @@ import { makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
import { addAddressBookEntry } from 'src/logic/addressBook/store/actions/addAddressBookEntry'
import { removeAddressBookEntry } from 'src/logic/addressBook/store/actions/removeAddressBookEntry'
import { updateAddressBookEntry } from 'src/logic/addressBook/store/actions/updateAddressBookEntry'
import { getAddressBookListSelector } from 'src/logic/addressBook/store/selectors'
import { getAddressBook } from 'src/logic/addressBook/store/selectors'
import { isUserAnOwnerOfAnySafe } from 'src/logic/wallets/ethAddresses'
import CreateEditEntryModal from 'src/routes/safe/components/AddressBook/CreateEditEntryModal'
import DeleteEntryModal from 'src/routes/safe/components/AddressBook/DeleteEntryModal'
@ -48,7 +48,7 @@ const AddressBookTable = ({ classes }) => {
const dispatch = useDispatch()
const safesList = useSelector(safesListSelector)
const entryAddressToEditOrCreateNew = useSelector(addressBookQueryParamsSelector)
const addressBook = useSelector(getAddressBookListSelector)
const addressBook = useSelector(getAddressBook)
const [selectedEntry, setSelectedEntry] = useState(null)
const [editCreateEntryModalOpen, setEditCreateEntryModalOpen] = useState(false)
const [deleteEntryModalOpen, setDeleteEntryModalOpen] = useState(false)

View File

@ -11,9 +11,10 @@ import { styles } from './style'
import Identicon from 'src/components/Identicon'
import { mustBeEthereumAddress, mustBeEthereumContractAddress } from 'src/components/forms/validator'
import { getAddressBookListSelector } from 'src/logic/addressBook/store/selectors'
import { getAddressBook } from 'src/logic/addressBook/store/selectors'
import { getAddressFromENS } from 'src/logic/wallets/getWeb3'
import { isValidEnsName } from 'src/logic/wallets/ethAddresses'
import { AddressBookEntryRecord } from 'src/logic/addressBook/model/addressBook'
export interface AddressBookProps {
fieldMutator: (address: string) => void
@ -45,11 +46,11 @@ const textFieldInputStyle = makeStyles(() => ({
}))
const filterAddressBookWithContractAddresses = async (
addressBook: List<{ address: string }>,
): Promise<List<{ address: string }>> => {
addressBook: List<AddressBookEntryRecord>,
): Promise<List<AddressBookEntryRecord>> => {
const abFlags = await Promise.all(
addressBook.map(
async ({ address }: { address: string }): Promise<boolean> => {
async ({ address }: AddressBookEntryRecord): Promise<boolean> => {
return (await mustBeEthereumContractAddress(address)) === undefined
},
),
@ -58,6 +59,11 @@ const filterAddressBookWithContractAddresses = async (
return addressBook.filter((_, index) => abFlags[index])
}
interface FilteredAddressBookEntry {
name: string
address: string
}
const AddressBookInput = ({
fieldMutator,
isCustomTx,
@ -67,12 +73,12 @@ const AddressBookInput = ({
setSelectedEntry,
}: AddressBookProps) => {
const classes = useStyles()
const addressBook = useSelector(getAddressBookListSelector)
const addressBook = useSelector(getAddressBook)
const [isValidForm, setIsValidForm] = useState(true)
const [validationText, setValidationText] = useState<string>('')
const [inputTouched, setInputTouched] = useState(false)
const [blurred, setBlurred] = useState(pristine)
const [adbkList, setADBKList] = useState<List<{ address: string }>>(List([]))
const [adbkList, setADBKList] = useState<List<FilteredAddressBookEntry>>(List([]))
const [inputAddValue, setInputAddValue] = useState(recipientAddress)
@ -146,7 +152,7 @@ const AddressBookInput = ({
<>
<Autocomplete
closeIcon={null}
disableOpenOnFocus
openOnFocus={false}
filterOptions={(optionsArray, { inputValue }) =>
optionsArray.filter((item) => {
const inputLowerCase = inputValue.toLowerCase()
@ -158,7 +164,7 @@ const AddressBookInput = ({
freeSolo
getOptionLabel={(adbkEntry) => adbkEntry.address || ''}
id="free-solo-demo"
onChange={(event, value) => {
onChange={(_, value: FilteredAddressBookEntry) => {
let address = ''
let name = ''
if (value) {
@ -220,7 +226,7 @@ const AddressBookInput = ({
}}
role="listbox"
style={{ display: 'flex', flexGrow: 1 }}
value={{ address: inputAddValue }}
value={{ address: inputAddValue, name: '' }}
/>
</>
)

View File

@ -38,7 +38,7 @@ type Props = {
const useStyles = makeStyles(styles)
const ReviewCustomTx = ({ onClose, onPrev, tx }: Props) => {
const ReviewCustomTx = ({ onClose, onPrev, tx }: Props): React.ReactElement => {
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
const classes = useStyles()
const dispatch = useDispatch()

View File

@ -87,18 +87,7 @@ const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedT
</IconButton>
</Row>
<Hairline />
<GnoForm
formMutators={formMutators}
initialValues={initialValues}
onSubmit={handleSubmit}
validation={(values) => {
const selectedTokenRecord = tokens.find((token) => token.address === values?.token)
return {
amount: maxValue(selectedTokenRecord?.balance)(values.amount),
}
}}
>
<GnoForm formMutators={formMutators} initialValues={initialValues} onSubmit={handleSubmit}>
{(...args) => {
const formState = args[2]
const mutators = args[3]

View File

@ -56,7 +56,7 @@ const RemoveModuleModal = ({ onClose, selectedModule }: RemoveModuleModal): Reac
try {
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const [module, prevModule] = selectedModule
const txData = safeInstance.contract.methods.disableModule(prevModule, module).encodeABI()
const txData = safeInstance.methods.disableModule(prevModule, module).encodeABI()
dispatch(
createTransaction({

View File

@ -27,7 +27,7 @@ const styles = () => ({
export const sendAddOwner = async (values, safeAddress, ownersOld, enqueueSnackbar, closeSnackbar, dispatch) => {
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const txData = gnosisSafe.contract.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
const txData = gnosisSafe.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
const txHash = await dispatch(
createTransaction({

View File

@ -40,9 +40,7 @@ const ReviewAddOwner = ({ classes, onClickBack, onClose, onSubmit, values }) =>
const { fromWei, toBN } = web3.utils
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const txData = safeInstance.contract.methods
.addOwnerWithThreshold(values.ownerAddress, values.threshold)
.encodeABI()
const txData = safeInstance.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether')

View File

@ -39,14 +39,12 @@ export const sendRemoveOwner = async (
dispatch,
) => {
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const safeOwners = await gnosisSafe.getOwners()
const safeOwners = await gnosisSafe.methods.getOwners().call()
const index = safeOwners.findIndex(
(ownerAddress) => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase(),
)
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
const txData = gnosisSafe.contract.methods
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
.encodeABI()
const txData = gnosisSafe.methods.removeOwner(prevAddress, ownerAddressToRemove, values.threshold).encodeABI()
const txHash = await dispatch(
createTransaction({

View File

@ -41,10 +41,10 @@ const ReviewRemoveOwner = ({ classes, onClickBack, onClose, onSubmit, ownerAddre
const web3 = getWeb3()
const { fromWei, toBN } = web3.utils
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const safeOwners = await gnosisSafe.getOwners()
const safeOwners = await gnosisSafe.methods.getOwners().call()
const index = safeOwners.findIndex((owner) => owner.toLowerCase() === ownerAddress.toLowerCase())
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
const txData = gnosisSafe.contract.methods.removeOwner(prevAddress, ownerAddress, values.threshold).encodeABI()
const txData = gnosisSafe.methods.removeOwner(prevAddress, ownerAddress, values.threshold).encodeABI()
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether')
const formattedGasCosts = formatAmount(gasCostsAsEth)

View File

@ -33,14 +33,12 @@ export const sendReplaceOwner = async (
dispatch,
) => {
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const safeOwners = await gnosisSafe.getOwners()
const safeOwners = await gnosisSafe.methods.getOwners().call()
const index = safeOwners.findIndex(
(ownerAddress) => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase(),
)
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
const txData = gnosisSafe.contract.methods
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
.encodeABI()
const txData = gnosisSafe.methods.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress).encodeABI()
const txHash = await dispatch(
createTransaction({

View File

@ -42,10 +42,10 @@ const ReviewRemoveOwner = ({ classes, onClickBack, onClose, onSubmit, ownerAddre
const web3 = getWeb3()
const { fromWei, toBN } = web3.utils
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
const safeOwners = await gnosisSafe.getOwners()
const safeOwners = await gnosisSafe.methods.getOwners().call()
const index = safeOwners.findIndex((owner) => owner.toLowerCase() === ownerAddress.toLowerCase())
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
const txData = gnosisSafe.contract.methods.swapOwner(prevAddress, ownerAddress, values.ownerAddress).encodeABI()
const txData = gnosisSafe.methods.swapOwner(prevAddress, ownerAddress, values.ownerAddress).encodeABI()
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether')
const formattedGasCosts = formatAmount(gasCostsAsEth)

View File

@ -32,7 +32,7 @@ const ChangeThreshold = ({ classes, onChangeThreshold, onClose, owners, safeAddr
const web3 = getWeb3()
const { fromWei, toBN } = web3.utils
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const txData = safeInstance.contract.methods.changeThreshold('1').encodeABI()
const txData = safeInstance.methods.changeThreshold('1').encodeABI()
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether')
const formattedGasCosts = formatAmount(gasCostsAsEth)

View File

@ -37,7 +37,7 @@ const ThresholdSettings = ({ classes, closeSnackbar, enqueueSnackbar }) => {
const onChangeThreshold = async (newThreshold) => {
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const txData = safeInstance.contract.methods.changeThreshold(newThreshold).encodeABI()
const txData = safeInstance.methods.changeThreshold(newThreshold).encodeABI()
dispatch(
createTransaction({

View File

@ -38,6 +38,7 @@ import fetchTransactions from './transactions/fetchTransactions'
import { safeTransactionsSelector } from 'src/routes/safe/store/selectors'
import { Transaction, TransactionStatus, TxArgs } from 'src/routes/safe/store/models/types/transaction'
import { AnyAction } from 'redux'
import { PayableTx } from 'src/types/contracts/types.d'
import { AppReduxState } from 'src/store'
import { Dispatch } from './types'
@ -136,7 +137,7 @@ const createTransaction = ({
const { account: from, hardwareWallet, smartContractWallet } = providerSelector(state)
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const lastTx = await getLastTx(safeAddress)
const nonce = Number(await getNewTxNonce(txNonce, lastTx, safeInstance))
const nonce = await getNewTxNonce(txNonce?.toString(), lastTx, safeInstance)
const isExecution = await shouldExecuteTransaction(safeInstance, nonce, lastTx)
const safeVersion = await getCurrentSafeVersion(safeInstance)
const safeTxGas = await estimateSafeTxGas(safeInstance, safeAddress, txData, to, valueInWei, operation)
@ -153,14 +154,13 @@ const createTransaction = ({
let pendingExecutionKey
let txHash
let tx
const txArgs: TxArgs = {
safeInstance,
to,
valueInWei,
data: txData,
operation,
nonce,
nonce: Number.parseInt(nonce),
safeTxGas,
baseGas: 0,
gasPrice: '0',
@ -189,9 +189,8 @@ const createTransaction = ({
}
}
tx = isExecution ? await getExecutionTransaction(txArgs) : await getApprovalTransaction(txArgs)
const sendParams: any = { from, value: 0 }
const tx = isExecution ? await getExecutionTransaction(txArgs) : await getApprovalTransaction(txArgs)
const sendParams: PayableTx = { from, value: 0 }
// if not set owner management tests will fail on ganache
if (process.env.NODE_ENV === 'test') {
@ -282,7 +281,7 @@ const createTransaction = ({
? `${notificationsQueue.afterExecutionError.message} - ${err.message}`
: notificationsQueue.afterExecutionError.message
console.error(err)
console.error(`Error creating the TX: `, err)
closeSnackbar(beforeExecutionKey)
if (pendingExecutionKey) {
@ -291,11 +290,11 @@ const createTransaction = ({
showSnackbar(errorMsg, enqueueSnackbar, closeSnackbar)
const executeDataUsedSignatures = safeInstance.contract.methods
const executeDataUsedSignatures = safeInstance.methods
.execTransaction(to, valueInWei, txData, operation, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs)
.encodeABI()
const errMsg = await getErrorMessage(safeInstance.address, 0, executeDataUsedSignatures, from)
console.error(`Error creating the TX: ${errMsg}`)
const errMsg = await getErrorMessage(safeInstance.options.address, 0, executeDataUsedSignatures, from)
console.error(`Error creating the TX - an attempt to get the error message: ${errMsg}`)
}
return txHash

View File

@ -35,6 +35,7 @@ const processTransaction = ({
const { account: from, hardwareWallet, smartContractWallet } = providerSelector(state)
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const lastTx = await getLastTx(safeAddress)
const nonce = await getNewTxNonce(null, lastTx, safeInstance)
const isExecution = approveAndExecute || (await shouldExecuteTransaction(safeInstance, nonce, lastTx))
@ -213,8 +214,8 @@ const processTransaction = ({
showSnackbar(errorMsg, enqueueSnackbar, closeSnackbar)
const executeData = safeInstance.contract.methods.approveHash(txHash).encodeABI()
const errMsg = await getErrorMessage(safeInstance.address, 0, executeData, from)
const executeData = safeInstance.methods.approveHash(txHash).encodeABI()
const errMsg = await getErrorMessage(safeInstance.options.address, 0, executeData, from)
console.error(`Error executing the TX: ${errMsg}`)
}
}

View File

@ -1,8 +1,10 @@
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
import { TxServiceModel } from './transactions/fetchTransactions/loadOutgoingTransactions'
import axios from 'axios'
import { buildTxServiceUrl } from 'src/logic/safe/transactions/txHistory'
export const getLastTx = async (safeAddress) => {
export const getLastTx = async (safeAddress: string): Promise<TxServiceModel> => {
try {
const url = buildTxServiceUrl(safeAddress)
const response = await axios.get(url, { params: { limit: 1 } })
@ -14,21 +16,29 @@ export const getLastTx = async (safeAddress) => {
}
}
export const getNewTxNonce = async (txNonce, lastTx, safeInstance) => {
export const getNewTxNonce = async (
txNonce: string | null,
lastTx: TxServiceModel,
safeInstance: GnosisSafe,
): Promise<string> => {
if (!Number.isInteger(Number.parseInt(txNonce, 10))) {
return lastTx === null
? // use current's safe nonce as fallback
(await safeInstance.nonce()).toString()
(await safeInstance.methods.nonce().call()).toString()
: `${lastTx.nonce + 1}`
}
return txNonce
}
export const shouldExecuteTransaction = async (safeInstance, nonce, lastTx) => {
const threshold = await safeInstance.getThreshold()
export const shouldExecuteTransaction = async (
safeInstance: GnosisSafe,
nonce: string,
lastTx: TxServiceModel,
): Promise<boolean> => {
const threshold = await safeInstance.methods.getThreshold().call()
// Tx will automatically be executed if and only if the threshold is 1
if (threshold.toNumber() === 1) {
if (Number.parseInt(threshold) === 1) {
const isFirstTransaction = Number.parseInt(nonce) === 0
// if the previous tx is not executed, it's delayed using the approval mechanisms,
// once the previous tx is executed, the current tx will be available to be executed

View File

@ -12,7 +12,7 @@ export type SafeRecordProps = {
address: string
threshold: number
ethBalance: string
owners: List<{ name: string; address: string }>
owners: List<SafeOwner>
modules: ModulePair[] | null
activeTokens: Set<string>
activeAssets: Set<string>

View File

@ -1,6 +1,7 @@
import { List, Map, RecordOf } from 'immutable'
import { DecodedMethods } from 'src/logic/contracts/methodIds'
import { Confirmation } from './confirmation'
import { GnosisSafe } from 'src/types/contracts/GnosisSafe.d'
export enum TransactionTypes {
INCOMING = 'incoming',
@ -88,7 +89,7 @@ export type TxArgs = {
nonce: number
operation: number
refundReceiver: string
safeInstance: any
safeInstance: GnosisSafe
safeTxGas: number
sender?: string
sigs: string

View File

@ -5,6 +5,7 @@ import thunk from 'redux-thunk'
import addressBookMiddleware from 'src/logic/addressBook/store/middleware/addressBookMiddleware'
import addressBook, { ADDRESS_BOOK_REDUCER_ID } from 'src/logic/addressBook/store/reducer/addressBook'
import { AddressBookReducerMap } from 'src/logic/addressBook/store/reducer/types/addressBook.d'
import {
NFT_ASSETS_REDUCER_ID,
NFT_TOKENS_REDUCER_ID,
@ -78,7 +79,7 @@ export type AppReduxState = CombinedState<{
[NOTIFICATIONS_REDUCER_ID]: Map<string, any>
[CURRENCY_VALUES_KEY]: Map<string, CurrencyRateValueRecord>
[COOKIES_REDUCER_ID]: Map<string, any>
[ADDRESS_BOOK_REDUCER_ID]: Map<string, any>
[ADDRESS_BOOK_REDUCER_ID]: AddressBookReducerMap
[CURRENT_SESSION_REDUCER_ID]: Map<string, any>
router: RouterState
}>

View File

@ -130,9 +130,9 @@ describe('DOM > Feature > CREATE a Safe', () => {
expect(address).not.toBe(undefined)
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const storedOwners = await gnosisSafe.getOwners()
const storedOwners = await gnosisSafe.methods.getOwners().call()
expect(storedOwners.length).toEqual(4)
const safeThreshold = await gnosisSafe.getThreshold()
const safeThreshold = await gnosisSafe.methods.getThreshold().call()
expect(Number(safeThreshold)).toEqual(4)
})
})

View File

@ -2,16 +2,6 @@
import abi from 'ethereumjs-abi'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
/*
console.log(`to[${to}] \n\n valieInWei[${valueInWei}] \n\n
data[${data}] \n\n operation[${operation}] \n\n sigs[${sigs}]`)
const gnosisSafe = await getGnosisSafeInstanceAt(address)
await printOutApprove("Remove owner 3", address, await gnosisSafe.getOwners(), tx.get('data'), tx.get('nonce'))
const txData =
await gnosisSafe.contract.execTransactionIfApproved.getData(address, 0, tx.get('data'), 0, tx.get('nonce'))
const err = await getErrorMessage(address, 0, txData, accounts[2])
*/
export const getErrorMessage = async (to, value, data, from) => {
const web3 = getWeb3()
const returnData: any = await web3.eth.call({

View File

@ -1,81 +0,0 @@
import React from 'react'
import Stepper from '@material-ui/core/Stepper'
import TestUtils from 'react-dom/test-utils'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import GnoStepper from 'src/components/Stepper'
export const printOutApprove = async (
subject,
address,
owners,
data,
nonce,
) => {
// eslint-disable-next-line
console.log(subject)
const gnosisSafe = await getGnosisSafeInstanceAt(address)
const transactionHash = await gnosisSafe.getTransactionHash(address, 0, data, 0, 0, 0, 0, 0, 0, nonce)
// eslint-disable-next-line
console.log(`EO transaction hash ${transactionHash}`)
await Promise.all(
owners.map(async (owner, index) => {
const approved = await gnosisSafe.isApproved(transactionHash, owner)
// eslint-disable-next-line
console.log(`EO transaction approved by owner index ${index}: ${approved}`)
}),
)
// eslint-disable-next-line
console.log(`EO transaction executed ${await gnosisSafe.isExecuted(transactionHash)}`)
}
const MAX_TIMES_EXECUTED = 35
const INTERVAL = 500
export const whenExecuted = (SafeDom, ParentComponent) => new Promise((resolve, reject) => {
let times = 0
const interval = setInterval(() => {
if (times >= MAX_TIMES_EXECUTED) {
clearInterval(interval)
reject()
}
// $FlowFixMe
const SafeComponent = TestUtils.findRenderedComponentWithType(SafeDom, ParentComponent)
// $FlowFixMe
const StepperComponent = TestUtils.findRenderedComponentWithType(SafeComponent, GnoStepper as any)
if (StepperComponent.props.finishedTransaction === true) {
clearInterval(interval)
resolve()
}
times += 1
}, INTERVAL)
})
export const whenOnNext = (
SafeDom,
ParentComponent,
position,
) => new Promise((resolve, reject) => {
let times = 0
const interval = setInterval(() => {
if (times >= MAX_TIMES_EXECUTED) {
clearInterval(interval)
reject()
}
// $FlowFixMe
const SafeComponent = TestUtils.findRenderedComponentWithType(SafeDom, ParentComponent)
// $FlowFixMe
const StepperComponent = TestUtils.findRenderedComponentWithType(SafeComponent, Stepper as any)
if (StepperComponent.props.activeStep === position) {
clearInterval(interval)
resolve()
}
times += 1
}, INTERVAL)
})

595
yarn.lock
View File

@ -1682,13 +1682,13 @@
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/lab@4.0.0-alpha.39":
version "4.0.0-alpha.39"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.39.tgz#715ec621111ce876f1744bde1e55018341c4be3e"
integrity sha512-TbYfqS0zWdOzH44K7x74+dcLlMe6o5zrIvvHA2y6IZ1l9a9/qLUZGLwBIOtkBPHDDDJ32rv/bOPzOGGbnxLUDw==
"@material-ui/lab@4.0.0-alpha.56":
version "4.0.0-alpha.56"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz#ff63080949b55b40625e056bbda05e130d216d34"
integrity sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.7.1"
"@material-ui/utils" "^4.10.2"
clsx "^1.0.4"
prop-types "^15.7.2"
react-is "^16.8.0"
@ -1730,7 +1730,7 @@
resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2"
integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==
"@material-ui/utils@^4.10.2", "@material-ui/utils@^4.7.1", "@material-ui/utils@^4.9.6":
"@material-ui/utils@^4.10.2", "@material-ui/utils@^4.9.6":
version "4.10.2"
resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.10.2.tgz#3fd5470ca61b7341f1e0468ac8f29a70bf6df321"
integrity sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==
@ -1946,10 +1946,10 @@
dom-accessibility-api "^0.4.6"
pretty-format "^25.5.0"
"@testing-library/jest-dom@5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.1.tgz#b9541d7625cec9e5feb647f49a96c43f7c055cdd"
integrity sha512-NHOHjDwyBoqM7mXjNLieSp/6vJ17DILzhNTw7+RarluaBkyWRzWgFj+d6xnd1adMBlwfQSeR2FWGTxHXCxeMSA==
"@testing-library/jest-dom@5.11.2":
version "5.11.2"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.11.2.tgz#c49de331555c70127b5d7fc97344ad5265f4c54c"
integrity sha512-s+rWJx+lanEGKqvOl4qJR0rGjCrxsEjj9qjxFlg4NV4/FRD7fnUUAWPHqwpyafNHfLYArs58FADgdn4UKmjFmw==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
@ -1970,10 +1970,10 @@
"@babel/runtime" "^7.10.3"
"@testing-library/dom" "^7.17.1"
"@testing-library/user-event@12.0.13":
version "12.0.13"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-12.0.13.tgz#585fbb1188df005d16eabd376c3f8e8eb2f2d35c"
integrity sha512-JvodPV7CGl2Izf/qWS+vAVKBB1ZNAPGEacabfEeLGfafLmiqXoGJCxNZC1ml3mNTj9tTsIjouHGc42gvlyRTtQ==
"@testing-library/user-event@12.0.17":
version "12.0.17"
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-12.0.17.tgz#51f48905d62b3c6960fe5ea7a46152d8440f1586"
integrity sha512-Et22bfgnLdowY0VSP8MQuCP9wdrqWMrm9OCXSi3q3rx7ctSvEsC/jYNbgK/MJdDSpVhNVnB+fqm1VhVlDDRN6A==
dependencies:
"@babel/runtime" "^7.10.2"
@ -2144,6 +2144,11 @@
xhr "^2.2.0"
xtend "^4.0.1"
"@typechain/web3-v1@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@typechain/web3-v1/-/web3-v1-1.0.0.tgz#842f925e45bdfb0d28e08c0e355f1c8efed7ea91"
integrity sha512-MM8PmsblePaxy5BCYEuPtR4ajigPf504VRQzZgFYqs6KuFnJxbOjF8jNYT12P6UvUX7us75Wc78QdbvOHbb4hA==
"@types/aria-query@^4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0"
@ -2182,7 +2187,7 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5":
"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.4", "@types/bn.js@^4.11.5":
version "4.11.6"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c"
integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==
@ -2300,26 +2305,48 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/mkdirp@^0.5.2":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f"
integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==
dependencies:
"@types/node" "*"
"@types/node@*":
version "14.0.24"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.24.tgz#b0f86f58564fa02a28b68f8b55d4cdec42e3b9d6"
integrity sha512-btt/oNOiDWcSuI721MdL8VQGnjsKjlTMdrKyTcLCKeQp/n4AAMFJ961wMbp+09y8WuGPClDEv07RIItdXKIXAA==
"@types/node@14.0.25":
version "14.0.25"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.25.tgz#7ad8b00a1206d6c9e94810e49f3115f0bcc30456"
integrity sha512-okMqUHqrMlGOxfDZliX1yFX5MV6qcd5PpRz96XYtjkM0Ws/hwg23FMUqt6pETrVRZS+EKUB5HY19mmo54EuQbA==
"@types/node@14.0.27":
version "14.0.27"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1"
integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==
"@types/node@^10.12.18":
version "10.17.28"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.28.tgz#0e36d718a29355ee51cec83b42d921299200f6d9"
integrity sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==
"@types/node@^10.3.2":
version "10.17.27"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.27.tgz#391cb391c75646c8ad2a7b6ed3bbcee52d1bdf19"
integrity sha512-J0oqm9ZfAXaPdwNXMMgAhylw5fhmXkToJd06vuDUSAgEDZ/n/69/69UmyBZbc+zT34UnShuDSBqvim3SPnozJg==
"@types/node@^12.0.12", "@types/node@^12.12.6":
"@types/node@^12.0.12":
version "12.12.51"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.51.tgz#446a67af8c5ff98947d7cef296484c6ad47ddb16"
integrity sha512-6ILqt8iNThALrxDv2Q4LyYFQxULQz96HKNIFd4s9QRQaiHINYeUpLqeU/2IU7YMtvipG1fQVAy//vY8/fX1Y9w==
"@types/node@^12.12.6":
version "12.12.50"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.50.tgz#e9b2e85fafc15f2a8aa8fdd41091b983da5fd6ee"
integrity sha512-5ImO01Fb8YsEOYpV+aeyGYztcYcjGsBvN4D7G5r1ef2cuQOpymjWNQi5V0rKHE6PC2ru3HkoUr/Br2/8GUA84w==
"@types/node@^12.6.1":
version "12.12.53"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.53.tgz#be0d375933c3d15ef2380dafb3b0350ea7021129"
integrity sha512-51MYTDTyCziHb70wtGNFRwB4l+5JNvdqzFSkbDvpbftEgVUBEE+T5f7pROhWMp/fxp07oNIEQZd5bbfAH22ohQ==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@ -2332,6 +2359,11 @@
dependencies:
"@types/node" "*"
"@types/prettier@^1.13.2":
version "1.19.1"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f"
integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==
"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
@ -2342,7 +2374,7 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react-dom@^16.9.8":
"@types/react-dom@^16.9.6":
version "16.9.8"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423"
integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==
@ -2398,6 +2430,13 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/resolve@^0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194"
integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==
dependencies:
"@types/node" "*"
"@types/secp256k1@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.1.tgz#fb3aa61a1848ad97d7425ff9dcba784549fca5a4"
@ -2453,12 +2492,12 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.7.0.tgz#0f91aa3c83d019591719e597fbdb73a59595a263"
integrity sha512-4OEcPON3QIx0ntsuiuFP/TkldmBGXf0uKxPQlGtS/W2F3ndYm8Vgdpj/woPJkzUc65gd3iR+qi3K8SDQP/obFg==
"@typescript-eslint/eslint-plugin@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.7.1.tgz#d144c49a9a0ffe8dd704bb179c243df76c111bc9"
integrity sha512-3DB9JDYkMrc8Au00rGFiJLK2Ja9CoMP6Ut0sHsXp3ZtSugjNxvSSHTnKLfo4o+QmjYBJqEznDqsG1zj4F2xnsg==
dependencies:
"@typescript-eslint/experimental-utils" "3.7.0"
"@typescript-eslint/experimental-utils" "3.7.1"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.0.0"
@ -2485,26 +2524,26 @@
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/experimental-utils@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.7.0.tgz#0ee21f6c48b2b30c63211da23827725078d5169a"
integrity sha512-xpfXXAfZqhhqs5RPQBfAFrWDHoNxD5+sVB5A46TF58Bq1hRfVROrWHcQHHUM9aCBdy9+cwATcvCbRg8aIRbaHQ==
"@typescript-eslint/experimental-utils@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.7.1.tgz#ab036caaed4c870d22531d41f9352f3147364d61"
integrity sha512-TqE97pv7HrqWcGJbLbZt1v59tcqsSVpWTOf1AqrWK7n8nok2sGgVtYRuGXeNeLw3wXlLEbY1MKP3saB2HsO/Ng==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/types" "3.7.0"
"@typescript-eslint/typescript-estree" "3.7.0"
"@typescript-eslint/types" "3.7.1"
"@typescript-eslint/typescript-estree" "3.7.1"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/parser@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.7.0.tgz#3e9cd9df9ea644536feb6e5acdb8279ecff96ce9"
integrity sha512-2LZauVUt7jAWkcIW7djUc3kyW+fSarNEuM3RF2JdLHR9BfX/nDEnyA4/uWz0wseoWVZbDXDF7iF9Jc342flNqQ==
"@typescript-eslint/parser@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.7.1.tgz#5d9ccecb116d12d9c6073e9861c57c9b1aa88128"
integrity sha512-W4QV/gXvfIsccN8225784LNOorcm7ch68Fi3V4Wg7gmkWSQRKevO4RrRqWo6N/Z/myK1QAiGgeaXN57m+R/8iQ==
dependencies:
"@types/eslint-visitor-keys" "^1.0.0"
"@typescript-eslint/experimental-utils" "3.7.0"
"@typescript-eslint/types" "3.7.0"
"@typescript-eslint/typescript-estree" "3.7.0"
"@typescript-eslint/experimental-utils" "3.7.1"
"@typescript-eslint/types" "3.7.1"
"@typescript-eslint/typescript-estree" "3.7.1"
eslint-visitor-keys "^1.1.0"
"@typescript-eslint/parser@^2.10.0":
@ -2517,10 +2556,10 @@
"@typescript-eslint/typescript-estree" "2.34.0"
eslint-visitor-keys "^1.1.0"
"@typescript-eslint/types@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.7.0.tgz#09897fab0cb95479c01166b10b2c03c224821077"
integrity sha512-reCaK+hyKkKF+itoylAnLzFeNYAEktB0XVfSQvf0gcVgpz1l49Lt6Vo9x4MVCCxiDydA0iLAjTF/ODH0pbfnpg==
"@typescript-eslint/types@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.7.1.tgz#90375606b2fd73c1224fe9e397ee151e28fa1e0c"
integrity sha512-PZe8twm5Z4b61jt7GAQDor6KiMhgPgf4XmUb9zdrwTbgtC/Sj29gXP1dws9yEn4+aJeyXrjsD9XN7AWFhmnUfg==
"@typescript-eslint/typescript-estree@2.34.0":
version "2.34.0"
@ -2535,13 +2574,13 @@
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/typescript-estree@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.7.0.tgz#66872e6da120caa4b64e6b4ca5c8702afc74738d"
integrity sha512-xr5oobkYRebejlACGr1TJ0Z/r0a2/HUf0SXqPvlgUMwiMqOCu/J+/Dr9U3T0IxpE5oLFSkqMx1FE/dKaZ8KsOQ==
"@typescript-eslint/typescript-estree@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.7.1.tgz#ce1ffbd0fa53f34d4ce851a7a364e392432f6eb3"
integrity sha512-m97vNZkI08dunYOr2lVZOHoyfpqRs0KDpd6qkGaIcLGhQ2WPtgHOd/eVbsJZ0VYCQvupKrObAGTOvk3tfpybYA==
dependencies:
"@typescript-eslint/types" "3.7.0"
"@typescript-eslint/visitor-keys" "3.7.0"
"@typescript-eslint/types" "3.7.1"
"@typescript-eslint/visitor-keys" "3.7.1"
debug "^4.1.1"
glob "^7.1.6"
is-glob "^4.0.1"
@ -2549,10 +2588,10 @@
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/visitor-keys@3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.7.0.tgz#ac0417d382a136e4571a0b0dcfe52088cb628177"
integrity sha512-k5PiZdB4vklUpUX4NBncn5RBKty8G3ihTY+hqJsCdMuD0v4jofI5xuqwnVcWxfv6iTm2P/dfEa2wMUnsUY8ODw==
"@typescript-eslint/visitor-keys@3.7.1":
version "3.7.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.7.1.tgz#b90191e74efdee656be8c5a30f428ed16dda46d1"
integrity sha512-xn22sQbEya+Utj2IqJHGLA3i1jDzR43RzWupxojbSWnj3nnPLavaQmWe5utw03CwYao3r00qzXfgJMGNkrzrAA==
dependencies:
eslint-visitor-keys "^1.1.0"
@ -3138,6 +3177,20 @@ arr-union@^3.1.0:
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
array-back@^1.0.3, array-back@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b"
integrity sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=
dependencies:
typical "^2.6.0"
array-back@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022"
integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==
dependencies:
typical "^2.6.1"
array-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
@ -4774,11 +4827,16 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001097:
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001093:
version "1.0.30001105"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001105.tgz#d2cb0b31e5cf2f3ce845033b61c5c01566549abf"
integrity sha512-JupOe6+dGMr7E20siZHIZQwYqrllxotAhiaej96y6x00b/48rPt42o+SzOSCPbrpsDWvRja40Hwrj0g0q6LZJg==
caniuse-lite@^1.0.30001097:
version "1.0.30001104"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001104.tgz#4e3d5b3b1dd3c3529f10cb7f519c62ba3e579f5d"
integrity sha512-pkpCg7dmI/a7WcqM2yfdOiT4Xx5tzyoHAXWsX5/HxZ3TemwDZs0QXdqbE0UPLPVy/7BeK7693YfzfRYfu1YVpg==
capture-exit@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4"
@ -5149,6 +5207,15 @@ command-exists@^1.2.8:
resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69"
integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==
command-line-args@^4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-4.0.7.tgz#f8d1916ecb90e9e121eda6428e41300bfb64cc46"
integrity sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==
dependencies:
array-back "^2.0.0"
find-replace "^1.0.3"
typical "^2.6.1"
commander@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e"
@ -6408,7 +6475,7 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
ejs@^3.0.2, ejs@^3.1.3:
ejs@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.3.tgz#514d967a8894084d18d3d47bd169a1c0560f093d"
integrity sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg==
@ -6730,7 +6797,7 @@ escape-goat@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
escape-html@^1.0.3, escape-html@~1.0.3:
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
@ -6909,10 +6976,10 @@ eslint-plugin-react@7.19.0:
string.prototype.matchall "^4.0.2"
xregexp "^4.3.0"
eslint-plugin-react@^7.20.3:
version "7.20.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.3.tgz#0590525e7eb83890ce71f73c2cf836284ad8c2f1"
integrity sha512-txbo090buDeyV0ugF3YMWrzLIUqpYTsWSDZV9xLSmExE1P/Kmgg9++PD931r+KEWS66O1c9R4srLVVHmeHpoAg==
eslint-plugin-react@^7.20.5:
version "7.20.5"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.5.tgz#29480f3071f64a04b2c3d99d9b460ce0f76fb857"
integrity sha512-ajbJfHuFnpVNJjhyrfq+pH1C0gLc2y94OiCbAXT5O0J0YCKaFEHDV8+3+mDOr+w8WguRX+vSs1bM2BDG0VLvCw==
dependencies:
array-includes "^3.1.1"
array.prototype.flatmap "^1.2.3"
@ -7173,7 +7240,7 @@ eth-lib@0.2.7:
elliptic "^6.4.0"
xhr-request-promise "^0.1.2"
eth-lib@0.2.8:
eth-lib@0.2.8, eth-lib@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8"
integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==
@ -8004,6 +8071,14 @@ find-cache-dir@^3.2.0:
make-dir "^3.0.2"
pkg-dir "^4.1.0"
find-replace@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0"
integrity sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=
dependencies:
array-back "^1.0.4"
test-value "^2.1.0"
find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
@ -8584,7 +8659,7 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
gzip-size@5.1.1, gzip-size@^5.1.1:
gzip-size@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274"
integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==
@ -12234,7 +12309,7 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
open@^7.0.2, open@^7.0.3, open@^7.1.0:
open@^7.0.2, open@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/open/-/open-7.1.0.tgz#68865f7d3cb238520fa1225a63cf28bcf8368a1c"
integrity sha512-lLPI5KgOwEYCDKXf4np7y1PBEkj7HYIyP2DY8mVDRnx0VIIu6bNrRB0R66TuO7Mack6EnTNLm4uvcl1UoklTpA==
@ -13537,6 +13612,11 @@ prettier@2.0.5:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
prettier@^1.14.2:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
pretty-bytes@^5.1.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
@ -14022,10 +14102,10 @@ react-qr-reader@^2.2.1:
prop-types "^15.7.2"
webrtc-adapter "^7.2.1"
react-redux@7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==
react-redux@7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985"
integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==
dependencies:
"@babel/runtime" "^7.5.5"
hoist-non-react-statics "^3.3.0"
@ -14744,7 +14824,7 @@ rgba-regex@^1.0.0:
resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3"
integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=
rimraf@2.6.3, rimraf@~2.6.2:
rimraf@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
@ -15433,24 +15513,6 @@ source-list-map@^2.0.0:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-explorer@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.4.2.tgz#fb23f86c3112eacde5683f24efaf4ddc9f677985"
integrity sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ==
dependencies:
btoa "^1.2.1"
chalk "^3.0.0"
convert-source-map "^1.7.0"
ejs "^3.0.2"
escape-html "^1.0.3"
glob "^7.1.6"
gzip-size "^5.1.1"
lodash "^4.17.15"
open "^7.0.3"
source-map "^0.7.3"
temp "^0.9.1"
yargs "^15.3.1"
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@ -16206,13 +16268,6 @@ temp-file@^3.3.7:
async-exit-hook "^2.0.1"
fs-extra "^8.1.0"
temp@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697"
integrity sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==
dependencies:
rimraf "~2.6.2"
term-size@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
@ -16267,6 +16322,14 @@ test-exclude@^5.2.3:
read-pkg-up "^4.0.0"
require-main-filename "^2.0.0"
test-value@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291"
integrity sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=
dependencies:
array-back "^1.0.3"
typical "^2.6.0"
text-table@0.2.0, text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -16499,7 +16562,16 @@ truffle-interface-adapter@^0.2.5:
lodash "^4.17.13"
web3 "1.2.1"
truffle@5.1.35, truffle@^5.1.21:
truffle@5.1.36:
version "5.1.36"
resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.1.36.tgz#d49c9e0c20558bdee76f442663f81367f62c5559"
integrity sha512-BXfDrRJmxECsHFu1ZHeQNDdv3OA3vmwQ6Wp5m9yaE0swKcHS+gd8sBdxQBoliiAI0xvUAsD62PRGowqFfT1CLg==
dependencies:
app-module-path "^2.2.0"
mocha "8.0.1"
original-require "1.0.1"
truffle@^5.1.21:
version "5.1.35"
resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.1.35.tgz#9b3adfd3aca1a3b6dd00874bc57d7569a3e3b89c"
integrity sha512-N2b/3OF84c/4jqmPJ4JgQU1g91Cai4JMKdJ3HLUsmEKmo1LZ84+Y0UIeVBFjWHtTX6H7/oXlvZ59xUVzxXyAsg==
@ -16515,6 +16587,31 @@ truncate-utf8-bytes@^1.0.0:
dependencies:
utf8-byte-length "^1.0.1"
ts-essentials@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a"
integrity sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==
ts-essentials@^6.0.3:
version "6.0.7"
resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-6.0.7.tgz#5f4880911b7581a873783740ce8b94da163d18a6"
integrity sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw==
ts-generator@^0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/ts-generator/-/ts-generator-0.0.8.tgz#7bd48ca064db026d9520bcb682b69efc20971d6a"
integrity sha512-Gi+aZCELpVL7Mqb+GuMgM+n8JZ/arZZib1iD/R9Ok8JDjOCOCrqS9b1lr72ku7J45WeDCFZxyJoRsiQvhokCnw==
dependencies:
"@types/mkdirp" "^0.5.2"
"@types/prettier" "^1.13.2"
"@types/resolve" "^0.0.8"
chalk "^2.4.1"
glob "^7.1.2"
mkdirp "^0.5.1"
prettier "^1.14.2"
resolve "^1.8.1"
ts-essentials "^1.0.0"
ts-pnp@1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a"
@ -16619,6 +16716,19 @@ type@^2.0.0:
resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
typechain@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/typechain/-/typechain-2.0.0.tgz#62143b48cdf8f95a777f1b76617af077b2d44eee"
integrity sha512-O+hsAUwtBpqCfoq46Grm52OEdm0GBEu78LxrEzkkGdwUdCoCZpNb2HPzPoNB1MXiRnNhEOGMFyf05UbT2/bUEw==
dependencies:
command-line-args "^4.0.7"
debug "^4.1.1"
fs-extra "^7.0.0"
js-sha3 "^0.8.0"
lodash "^4.17.15"
ts-essentials "^6.0.3"
ts-generator "^0.0.8"
typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5:
version "3.1.5"
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
@ -16631,11 +16741,16 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.9.7:
typescript@3.9.7:
version "3.9.7"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
typical@^2.6.0, typical@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d"
integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=
u2f-api@0.2.7:
version "0.2.7"
resolved "https://registry.yarnpkg.com/u2f-api/-/u2f-api-0.2.7.tgz#17bf196b242f6bf72353d9858e6a7566cc192720"
@ -17079,12 +17194,12 @@ web3-bzz@1.2.1:
swarm-js "0.1.39"
underscore "1.9.1"
web3-bzz@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f"
integrity sha512-XGpWUEElGypBjeFyUhTkiPXFbDVD6Nr/S5jznE3t8cWUA0FxRf1n3n/NuIZeb0H9RkN2Ctd/jNma/k8XGa3YKg==
web3-bzz@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.9.tgz#25f8a373bc2dd019f47bf80523546f98b93c8790"
integrity sha512-ogVQr9jHodu9HobARtvUSmWG22cv2EUQzlPeejGWZ7j5h20HX40EDuWyomGY5VclIj5DdLY76Tmq88RTf/6nxA==
dependencies:
"@types/node" "^12.12.6"
"@types/node" "^10.12.18"
got "9.6.0"
swarm-js "^0.1.40"
underscore "1.9.1"
@ -17107,6 +17222,15 @@ web3-core-helpers@1.2.11:
web3-eth-iban "1.2.11"
web3-utils "1.2.11"
web3-core-helpers@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.9.tgz#6381077c3e01c127018cb9e9e3d1422697123315"
integrity sha512-t0WAG3orLCE3lqi77ZoSRNFok3VQWZXTniZigDQjyOJYMAX7BU3F3js8HKbjVnAxlX3tiKoDxI0KBk9F3AxYuw==
dependencies:
underscore "1.9.1"
web3-eth-iban "1.2.9"
web3-utils "1.2.9"
web3-core-method@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.1.tgz#9df1bafa2cd8be9d9937e01c6a47fc768d15d90a"
@ -17130,6 +17254,18 @@ web3-core-method@1.2.11:
web3-core-subscriptions "1.2.11"
web3-utils "1.2.11"
web3-core-method@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.9.tgz#3fb538751029bea570e4f86731e2fa5e4945e462"
integrity sha512-bjsIoqP3gs7A/gP8+QeLUCyOKJ8bopteCSNbCX36Pxk6TYfYWNuC6hP+2GzUuqdP3xaZNe+XEElQFUNpR3oyAg==
dependencies:
"@ethersproject/transactions" "^5.0.0-beta.135"
underscore "1.9.1"
web3-core-helpers "1.2.9"
web3-core-promievent "1.2.9"
web3-core-subscriptions "1.2.9"
web3-utils "1.2.9"
web3-core-promievent@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz#003e8a3eb82fb27b6164a6d5b9cad04acf733838"
@ -17145,6 +17281,13 @@ web3-core-promievent@1.2.11:
dependencies:
eventemitter3 "4.0.4"
web3-core-promievent@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.9.tgz#bb1c56aa6fac2f4b3c598510f06554d25c11c553"
integrity sha512-0eAUA2zjgXTleSrnc1wdoKQPPIHU6KHf4fAscu4W9kKrR+mqP1KsjYrxY9wUyjNnXxfQ+5M29ipvbiaK8OqdOw==
dependencies:
eventemitter3 "3.1.2"
web3-core-requestmanager@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz#fa2e2206c3d738db38db7c8fe9c107006f5c6e3d"
@ -17167,6 +17310,17 @@ web3-core-requestmanager@1.2.11:
web3-providers-ipc "1.2.11"
web3-providers-ws "1.2.11"
web3-core-requestmanager@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.9.tgz#dd6d855256c4dd681434fe0867f8cd742fe10503"
integrity sha512-1PwKV2m46ALUnIN5VPPgjOj8yMLJhhqZYvYJE34hTN5SErOkwhzx5zScvo5MN7v7KyQGFnpVCZKKGCiEnDmtFA==
dependencies:
underscore "1.9.1"
web3-core-helpers "1.2.9"
web3-providers-http "1.2.9"
web3-providers-ipc "1.2.9"
web3-providers-ws "1.2.9"
web3-core-subscriptions@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz#8c2368a839d4eec1c01a4b5650bbeb82d0e4a099"
@ -17185,6 +17339,15 @@ web3-core-subscriptions@1.2.11:
underscore "1.9.1"
web3-core-helpers "1.2.11"
web3-core-subscriptions@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.9.tgz#335fd7d15dfce5d78b4b7bef05ce4b3d7237b0e4"
integrity sha512-Y48TvXPSPxEM33OmXjGVDMzTd0j8X0t2+sDw66haeBS8eYnrEzasWuBZZXDq0zNUsqyxItgBGDn+cszkgEnFqg==
dependencies:
eventemitter3 "3.1.2"
underscore "1.9.1"
web3-core-helpers "1.2.9"
web3-core@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.1.tgz#7278b58fb6495065e73a77efbbce781a7fddf1a9"
@ -17195,7 +17358,7 @@ web3-core@1.2.1:
web3-core-requestmanager "1.2.1"
web3-utils "1.2.1"
web3-core@1.2.11:
web3-core@1.2.11, web3-core@^1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7"
integrity sha512-CN7MEYOY5ryo5iVleIWRE3a3cZqVaLlIbIzDPsvQRUfzYnvzZQRZBm9Mq+ttDi2STOOzc1MKylspz/o3yq/LjQ==
@ -17208,6 +17371,19 @@ web3-core@1.2.11:
web3-core-requestmanager "1.2.11"
web3-utils "1.2.11"
web3-core@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.9.tgz#2cba57aa259b6409db532d21bdf57db8d504fd3e"
integrity sha512-fSYv21IP658Ty2wAuU9iqmW7V+75DOYMVZsDH/c14jcF/1VXnedOcxzxSj3vArsCvXZNe6XC5/wAuGZyQwR9RA==
dependencies:
"@types/bn.js" "^4.11.4"
"@types/node" "^12.6.1"
bignumber.js "^9.0.0"
web3-core-helpers "1.2.9"
web3-core-method "1.2.9"
web3-core-requestmanager "1.2.9"
web3-utils "1.2.9"
web3-eth-abi@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz#9b915b1c9ebf82f70cca631147035d5419064689"
@ -17226,6 +17402,15 @@ web3-eth-abi@1.2.11:
underscore "1.9.1"
web3-utils "1.2.11"
web3-eth-abi@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.9.tgz#14bedd7e4be04fcca35b2ac84af1400574cd8280"
integrity sha512-3YwUYbh/DMfDbhMWEebAdjSd5bj3ZQieOjLzWFHU23CaLEqT34sUix1lba+hgUH/EN6A7bKAuKOhR3p0OvTn7Q==
dependencies:
"@ethersproject/abi" "5.0.0-beta.153"
underscore "1.9.1"
web3-utils "1.2.9"
web3-eth-accounts@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz#2741a8ef337a7219d57959ac8bd118b9d68d63cf"
@ -17243,22 +17428,22 @@ web3-eth-accounts@1.2.1:
web3-core-method "1.2.1"
web3-utils "1.2.1"
web3-eth-accounts@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520"
integrity sha512-6FwPqEpCfKIh3nSSGeo3uBm2iFSnFJDfwL3oS9pyegRBXNsGRVpgiW63yhNzL0796StsvjHWwQnQHsZNxWAkGw==
web3-eth-accounts@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.9.tgz#7ec422df90fecb5243603ea49dc28726db7bdab6"
integrity sha512-jkbDCZoA1qv53mFcRHCinoCsgg8WH+M0YUO1awxmqWXRmCRws1wW0TsuSQ14UThih5Dxolgl+e+aGWxG58LMwg==
dependencies:
crypto-browserify "3.12.0"
eth-lib "0.2.8"
eth-lib "^0.2.8"
ethereumjs-common "^1.3.2"
ethereumjs-tx "^2.1.1"
scrypt-js "^3.0.1"
underscore "1.9.1"
uuid "3.3.2"
web3-core "1.2.11"
web3-core-helpers "1.2.11"
web3-core-method "1.2.11"
web3-utils "1.2.11"
web3-core "1.2.9"
web3-core-helpers "1.2.9"
web3-core-method "1.2.9"
web3-utils "1.2.9"
web3-eth-contract@1.2.1:
version "1.2.1"
@ -17274,7 +17459,22 @@ web3-eth-contract@1.2.1:
web3-eth-abi "1.2.1"
web3-utils "1.2.1"
web3-eth-contract@1.2.11, web3-eth-contract@^1.2.11, web3-eth-contract@^1.2.9:
web3-eth-contract@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.9.tgz#713d9c6d502d8c8f22b696b7ffd8e254444e6bfd"
integrity sha512-PYMvJf7EG/HyssUZa+pXrc8IB06K/YFfWYyW4R7ed3sab+9wWUys1TlWxBCBuiBXOokSAyM6H6P6/cKEx8FT8Q==
dependencies:
"@types/bn.js" "^4.11.4"
underscore "1.9.1"
web3-core "1.2.9"
web3-core-helpers "1.2.9"
web3-core-method "1.2.9"
web3-core-promievent "1.2.9"
web3-core-subscriptions "1.2.9"
web3-eth-abi "1.2.9"
web3-utils "1.2.9"
web3-eth-contract@^1.2.11, web3-eth-contract@^1.2.9:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90"
integrity sha512-MzYuI/Rq2o6gn7vCGcnQgco63isPNK5lMAan2E51AJLknjSLnOxwNY3gM8BcKoy4Z+v5Dv00a03Xuk78JowFow==
@ -17303,20 +17503,20 @@ web3-eth-ens@1.2.1:
web3-eth-contract "1.2.1"
web3-utils "1.2.1"
web3-eth-ens@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532"
integrity sha512-dbW7dXP6HqT1EAPvnniZVnmw6TmQEKF6/1KgAxbo8iBBYrVTMDGFQUUnZ+C4VETGrwwaqtX4L9d/FrQhZ6SUiA==
web3-eth-ens@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.9.tgz#577b9358c036337833fb2bdc59c11be7f6f731b6"
integrity sha512-kG4+ZRgZ8I1WYyOBGI8QVRHfUSbbJjvJAGA1AF/NOW7JXQ+x7gBGeJw6taDWJhSshMoEKWcsgvsiuoG4870YxQ==
dependencies:
content-hash "^2.5.2"
eth-ens-namehash "2.0.8"
underscore "1.9.1"
web3-core "1.2.11"
web3-core-helpers "1.2.11"
web3-core-promievent "1.2.11"
web3-eth-abi "1.2.11"
web3-eth-contract "1.2.11"
web3-utils "1.2.11"
web3-core "1.2.9"
web3-core-helpers "1.2.9"
web3-core-promievent "1.2.9"
web3-eth-abi "1.2.9"
web3-eth-contract "1.2.9"
web3-utils "1.2.9"
web3-eth-iban@1.2.1:
version "1.2.1"
@ -17334,6 +17534,14 @@ web3-eth-iban@1.2.11:
bn.js "^4.11.9"
web3-utils "1.2.11"
web3-eth-iban@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.9.tgz#4ebf3d8783f34d04c4740dc18938556466399f7a"
integrity sha512-RtdVvJE0pyg9dHLy0GzDiqgnLnssSzfz/JYguhC1wsj9+Gnq1M6Diy3NixACWUAp6ty/zafyOaZnNQ+JuH9TjQ==
dependencies:
bn.js "4.11.8"
web3-utils "1.2.9"
web3-eth-personal@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz#244e9911b7b482dc17c02f23a061a627c6e47faf"
@ -17345,17 +17553,17 @@ web3-eth-personal@1.2.1:
web3-net "1.2.1"
web3-utils "1.2.1"
web3-eth-personal@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70"
integrity sha512-42IzUtKq9iHZ8K9VN0vAI50iSU9tOA1V7XU2BhF/tb7We2iKBVdkley2fg26TxlOcKNEHm7o6HRtiiFsVK4Ifw==
web3-eth-personal@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.9.tgz#9b95eb159b950b83cd8ae15873e1d57711b7a368"
integrity sha512-cFiNrktxZ1C/rIdJFzQTvFn3/0zcsR3a+Jf8Y3KxeQDHszQtosjLWptP7bsUmDwEh4hzh0Cy3KpOxlYBWB8bJQ==
dependencies:
"@types/node" "^12.12.6"
web3-core "1.2.11"
web3-core-helpers "1.2.11"
web3-core-method "1.2.11"
web3-net "1.2.11"
web3-utils "1.2.11"
"@types/node" "^12.6.1"
web3-core "1.2.9"
web3-core-helpers "1.2.9"
web3-core-method "1.2.9"
web3-net "1.2.9"
web3-utils "1.2.9"
web3-eth@1.2.1:
version "1.2.1"
@ -17376,24 +17584,24 @@ web3-eth@1.2.1:
web3-net "1.2.1"
web3-utils "1.2.1"
web3-eth@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793"
integrity sha512-REvxW1wJ58AgHPcXPJOL49d1K/dPmuw4LjPLBPStOVkQjzDTVmJEIsiLwn2YeuNDd4pfakBwT8L3bz1G1/wVsQ==
web3-eth@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.9.tgz#e40e7b88baffc9b487193211c8b424dc944977b3"
integrity sha512-sIKO4iE9FEBa/CYUd6GdPd7GXt/wISqxUd8PlIld6+hvMJj02lgO7Z7p5T9mZIJcIZJGvZX81ogx8oJ9yif+Ag==
dependencies:
underscore "1.9.1"
web3-core "1.2.11"
web3-core-helpers "1.2.11"
web3-core-method "1.2.11"
web3-core-subscriptions "1.2.11"
web3-eth-abi "1.2.11"
web3-eth-accounts "1.2.11"
web3-eth-contract "1.2.11"
web3-eth-ens "1.2.11"
web3-eth-iban "1.2.11"
web3-eth-personal "1.2.11"
web3-net "1.2.11"
web3-utils "1.2.11"
web3-core "1.2.9"
web3-core-helpers "1.2.9"
web3-core-method "1.2.9"
web3-core-subscriptions "1.2.9"
web3-eth-abi "1.2.9"
web3-eth-accounts "1.2.9"
web3-eth-contract "1.2.9"
web3-eth-ens "1.2.9"
web3-eth-iban "1.2.9"
web3-eth-personal "1.2.9"
web3-net "1.2.9"
web3-utils "1.2.9"
web3-net@1.2.1:
version "1.2.1"
@ -17404,14 +17612,14 @@ web3-net@1.2.1:
web3-core-method "1.2.1"
web3-utils "1.2.1"
web3-net@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b"
integrity sha512-sjrSDj0pTfZouR5BSTItCuZ5K/oZPVdVciPQ6981PPPIwJJkCMeVjD7I4zO3qDPCnBjBSbWvVnLdwqUBPtHxyg==
web3-net@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.9.tgz#51d248ed1bc5c37713c4ac40c0073d9beacd87d3"
integrity sha512-d2mTn8jPlg+SI2hTj2b32Qan6DmtU9ap/IUlJTeQbZQSkTLf0u9suW8Vjwyr4poJYXTurdSshE7OZsPNn30/ZA==
dependencies:
web3-core "1.2.11"
web3-core-method "1.2.11"
web3-utils "1.2.11"
web3-core "1.2.9"
web3-core-method "1.2.9"
web3-utils "1.2.9"
web3-provider-engine@15.0.12, web3-provider-engine@^15.0.4:
version "15.0.12"
@ -17485,6 +17693,14 @@ web3-providers-http@1.2.11:
web3-core-helpers "1.2.11"
xhr2-cookies "1.1.0"
web3-providers-http@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.9.tgz#e698aa5377e2019c24c5a1e6efa0f51018728934"
integrity sha512-F956tCIj60Ttr0UvEHWFIhx+be3He8msoPzyA44/kfzzYoMAsCFRn5cf0zQG6al0znE75g6HlWVSN6s3yAh51A==
dependencies:
web3-core-helpers "1.2.9"
xhr2-cookies "1.1.0"
web3-providers-ipc@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz#017bfc687a8fc5398df2241eb98f135e3edd672c"
@ -17503,6 +17719,15 @@ web3-providers-ipc@1.2.11:
underscore "1.9.1"
web3-core-helpers "1.2.11"
web3-providers-ipc@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.9.tgz#6159eacfcd7ac31edc470d93ef10814fe874763b"
integrity sha512-NQ8QnBleoHA2qTJlqoWu7EJAD/FR5uimf7Ielzk4Z2z+m+6UAuJdJMSuQNj+Umhz9L/Ys6vpS1vHx9NizFl+aQ==
dependencies:
oboe "2.1.4"
underscore "1.9.1"
web3-core-helpers "1.2.9"
web3-providers-ws@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz#2d941eaf3d5a8caa3214eff8dc16d96252b842cb"
@ -17522,6 +17747,16 @@ web3-providers-ws@1.2.11:
web3-core-helpers "1.2.11"
websocket "^1.0.31"
web3-providers-ws@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.9.tgz#22c2006655ec44b4ad2b41acae62741a6ae7a88c"
integrity sha512-6+UpvINeI//dglZoAKStUXqxDOXJy6Iitv2z3dbgInG4zb8tkYl/VBDL80UjUg3ZvzWG0g7EKY2nRPEpON2TFA==
dependencies:
eventemitter3 "^4.0.0"
underscore "1.9.1"
web3-core-helpers "1.2.9"
websocket "^1.0.31"
web3-shh@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.1.tgz#4460e3c1e07faf73ddec24ccd00da46f89152b0c"
@ -17532,15 +17767,15 @@ web3-shh@1.2.1:
web3-core-subscriptions "1.2.1"
web3-net "1.2.1"
web3-shh@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f"
integrity sha512-B3OrO3oG1L+bv3E1sTwCx66injW1A8hhwpknDUbV+sw3fehFazA06z9SGXUefuFI1kVs4q2vRi0n4oCcI4dZDg==
web3-shh@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.9.tgz#c4ba70d6142cfd61341a50752d8cace9a0370911"
integrity sha512-PWa8b/EaxaMinFaxy6cV0i0EOi2M7a/ST+9k9nhyhCjVa2vzXuNoBNo2IUOmeZ0WP2UQB8ByJ2+p4htlJaDOjA==
dependencies:
web3-core "1.2.11"
web3-core-method "1.2.11"
web3-core-subscriptions "1.2.11"
web3-net "1.2.11"
web3-core "1.2.9"
web3-core-method "1.2.9"
web3-core-subscriptions "1.2.9"
web3-net "1.2.9"
web3-utils@1.2.1:
version "1.2.1"
@ -17569,6 +17804,20 @@ web3-utils@1.2.11, web3-utils@^1.2.11, web3-utils@^1.2.9:
underscore "1.9.1"
utf8 "3.0.0"
web3-utils@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.9.tgz#abe11735221627da943971ef1a630868fb9c61f3"
integrity sha512-9hcpuis3n/LxFzEVjwnVgvJzTirS2S9/MiNAa7l4WOEoywY+BSNwnRX4MuHnjkh9NY25B6QOjuNG6FNnSjTw1w==
dependencies:
bn.js "4.11.8"
eth-lib "0.2.7"
ethereum-bloom-filters "^1.0.6"
ethjs-unit "0.1.6"
number-to-bn "1.7.0"
randombytes "^2.1.0"
underscore "1.9.1"
utf8 "3.0.0"
web3@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.1.tgz#5d8158bcca47838ab8c2b784a2dee4c3ceb4179b"
@ -17582,18 +17831,18 @@ web3@1.2.1:
web3-shh "1.2.1"
web3-utils "1.2.1"
web3@1.2.11:
version "1.2.11"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975"
integrity sha512-mjQ8HeU41G6hgOYm1pmeH0mRAeNKJGnJEUzDMoerkpw7QUQT4exVREgF1MYPvL/z6vAshOXei25LE/t/Bxl8yQ==
web3@1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.9.tgz#cbcf1c0fba5e213a6dfb1f2c1f4b37062e4ce337"
integrity sha512-Mo5aBRm0JrcNpN/g4VOrDzudymfOnHRC3s2VarhYxRA8aWgF5rnhQ0ziySaugpic1gksbXPe105pUWyRqw8HUA==
dependencies:
web3-bzz "1.2.11"
web3-core "1.2.11"
web3-eth "1.2.11"
web3-eth-personal "1.2.11"
web3-net "1.2.11"
web3-shh "1.2.11"
web3-utils "1.2.11"
web3-bzz "1.2.9"
web3-core "1.2.9"
web3-eth "1.2.9"
web3-eth-personal "1.2.9"
web3-net "1.2.9"
web3-shh "1.2.9"
web3-utils "1.2.9"
web3@^0.20.7:
version "0.20.7"