Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge the develop branch to the master branch, preparation to v3.5.0 #647

Merged
merged 5 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions alm/src/components/ConfirmationsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const ConfirmationsContainer = ({
home: { name: homeName },
foreign: { name: foreignName }
} = useStateProvider()
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
const { requiredSignatures, validatorList } = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0)
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
const {
confirmations,
Expand Down Expand Up @@ -121,7 +121,7 @@ export const ConfirmationsContainer = ({
/>
{signatureCollected && (
<ExecutionConfirmation
messageData={message.data}
message={message}
executionData={executionData}
isHome={!fromHome}
signatureCollected={signatureCollected}
Expand Down
34 changes: 30 additions & 4 deletions alm/src/components/ExecutionConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { Thead, AgeTd, StatusTd } from './commons/Table'
import { ManualExecutionButton } from './ManualExecutionButton'
import { useStateProvider } from '../state/StateProvider'
import { matchesRule, MessageObject, WarnRule } from '../utils/web3'
import { WarningAlert } from './commons/WarningAlert'
import { ErrorAlert } from './commons/ErrorAlert'

const StyledExecutionConfirmation = styled.div`
margin-top: 30px;
`

export interface ExecutionConfirmationParams {
messageData: string
message: MessageObject
executionData: ExecutionData
setExecutionData: Function
signatureCollected: boolean | string[]
Expand All @@ -26,7 +29,7 @@ export interface ExecutionConfirmationParams {
}

export const ExecutionConfirmation = ({
messageData,
message,
executionData,
setExecutionData,
signatureCollected,
Expand All @@ -36,6 +39,8 @@ export const ExecutionConfirmation = ({
}: ExecutionConfirmationParams) => {
const { foreign } = useStateProvider()
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
const [error, setError] = useState('')
const [warning, setWarning] = useState('')
const availableManualExecution =
!isHome &&
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
Expand Down Expand Up @@ -67,9 +72,27 @@ export const ExecutionConfirmation = ({
[availableManualExecution, foreign.bridgeContract]
)

useEffect(
() => {
if (!message.data || !executionData || !availableManualExecution) return

try {
const fileName = 'warnRules'
const rules: WarnRule[] = require(`../snapshots/${fileName}.json`)
for (let rule of rules) {
if (matchesRule(rule, message)) {
setWarning(rule.message)
return
}
}
} catch (e) {}
},
[availableManualExecution, executionData, message, message.data, setWarning]
)

const getExecutionStatusElement = (validatorStatus = '') => {
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
case VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS:
return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return <RedLabel>{validatorStatus}</RedLabel>
Expand All @@ -87,6 +110,8 @@ export const ExecutionConfirmation = ({

return (
<StyledExecutionConfirmation>
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
{warning && <WarningAlert onClick={() => setWarning('')} error={warning} />}
<table>
<Thead>
<tr>
Expand Down Expand Up @@ -125,10 +150,11 @@ export const ExecutionConfirmation = ({
<td>
<ManualExecutionButton
safeExecutionAvailable={safeExecutionAvailable}
messageData={messageData}
messageData={message.data}
setExecutionData={setExecutionData}
signatureCollected={signatureCollected as string[]}
setPendingExecution={setPendingExecution}
setError={setError}
/>
</td>
)}
Expand Down
4 changes: 1 addition & 3 deletions alm/src/components/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { TransactionReceipt } from 'web3-eth'
import { InfoAlert } from './commons/InfoAlert'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
import { ErrorAlert } from './commons/ErrorAlert'

const StyledMainPage = styled.div`
text-align: center;
Expand Down Expand Up @@ -52,7 +51,7 @@ export interface FormSubmitParams {

export const MainPage = () => {
const history = useHistory()
const { home, foreign, error, setError } = useStateProvider()
const { home, foreign } = useStateProvider()
const [networkName, setNetworkName] = useState('')
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
const [showInfoAlert, setShowInfoAlert] = useState(false)
Expand Down Expand Up @@ -132,7 +131,6 @@ export const MainPage = () => {
</AlertP>
</InfoAlert>
)}
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
<Route
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}
Expand Down
90 changes: 81 additions & 9 deletions alm/src/components/ManualExecutionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useStateProvider } from '../state/StateProvider'
import { signatureToVRS, packSignatures } from '../utils/signatures'
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
import { TransactionReceipt } from 'web3-eth'
import { useValidatorContract } from '../hooks/useValidatorContract'

const ActionButton = styled.button`
color: var(--button-color);
Expand All @@ -32,20 +33,90 @@ interface ManualExecutionButtonParams {
setExecutionData: Function
signatureCollected: string[]
setPendingExecution: Function
setError: Function
}

export const ManualExecutionButton = ({
safeExecutionAvailable,
messageData,
setExecutionData,
signatureCollected,
setPendingExecution
setPendingExecution,
setError
}: ManualExecutionButtonParams) => {
const { foreign, setError } = useStateProvider()
const { foreign } = useStateProvider()
const { library, activate, account, active } = useWeb3React()
const [manualExecution, setManualExecution] = useState(false)
const [allowFailures, setAllowFailures] = useState(false)
const notReady = !foreign.bridgeContract || !signatureCollected || !signatureCollected.length
const [ready, setReady] = useState(false)
const [title, setTitle] = useState('Loading')
const [validSignatures, setValidSignatures] = useState<string[]>([])

const { requiredSignatures, validatorList } = useValidatorContract(false, 'latest')

useEffect(
() => {
if (
!foreign.bridgeContract ||
!foreign.web3 ||
!signatureCollected ||
!signatureCollected.length ||
!requiredSignatures ||
!validatorList ||
!validatorList.length
)
return

const signatures = []
const remainingValidators = Object.fromEntries(validatorList.map(validator => [validator, true]))
for (let i = 0; i < signatureCollected.length && signatures.length < requiredSignatures; i++) {
const { v, r, s } = signatureToVRS(signatureCollected[i])
const signer = foreign.web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
if (validatorList.includes(signer)) {
delete remainingValidators[signer]
signatures.push(signatureCollected[i])
}
}

if (signatures.length < requiredSignatures) {
console.log('On-chain collected signatures are not enough for message execution')
const manualValidators = Object.keys(remainingValidators)
const msgHash = foreign.web3.utils.sha3(messageData)!
for (let i = 0; i < manualValidators.length && signatures.length < requiredSignatures; i++) {
try {
const overrideSignatures: {
[key: string]: string
} = require(`../snapshots/signatures_${manualValidators[i]}.json`)
if (overrideSignatures[msgHash]) {
console.log(`Adding manual signature from ${manualValidators[i]}`)
signatures.push(overrideSignatures[msgHash])
} else {
console.log(`No manual signature from ${manualValidators[i]} was found`)
}
} catch (e) {
console.log(`Signatures overrides are not present for ${manualValidators[i]}`)
}
}
}

if (signatures.length >= requiredSignatures) {
setValidSignatures(signatures)
setTitle('Execute')
setReady(true)
} else {
setTitle('Unavailable')
}
},
[
foreign.bridgeContract,
foreign.web3,
signatureCollected,
validatorList,
requiredSignatures,
messageData,
setValidSignatures
]
)

useEffect(
() => {
Expand Down Expand Up @@ -73,9 +144,9 @@ export const ManualExecutionButton = ({
return
}

if (!library || !foreign.bridgeContract || !signatureCollected || !signatureCollected.length) return
if (!library || !foreign.bridgeContract || !foreign.web3 || !validSignatures || !validSignatures.length) return

const signatures = packSignatures(signatureCollected.map(signatureToVRS))
const signatures = packSignatures(validSignatures.map(signatureToVRS))
const messageId = messageData.slice(0, 66)
const bridge = foreign.bridgeContract
const executeMethod =
Expand Down Expand Up @@ -140,19 +211,20 @@ export const ManualExecutionButton = ({
foreign.bridgeContract,
setError,
messageData,
signatureCollected,
setExecutionData,
setPendingExecution,
safeExecutionAvailable,
allowFailures
allowFailures,
foreign.web3,
validSignatures
]
)

return (
<div>
<div className="is-center">
<ActionButton disabled={notReady} className="button outline" onClick={() => setManualExecution(true)}>
Execute
<ActionButton disabled={!ready} className="button outline" onClick={() => setManualExecution(true)}>
{title}
</ActionButton>
</div>
{safeExecutionAvailable && (
Expand Down
2 changes: 1 addition & 1 deletion alm/src/components/ValidatorsConfirmations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const ValidatorsConfirmations = ({
</tbody>
</table>
<RequiredConfirmations>
{requiredSignatures} of {validatorList.length} confirmations required
At least <strong>{requiredSignatures}</strong> of <strong>{validatorList.length}</strong> confirmations required
</RequiredConfirmations>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion alm/src/components/commons/ErrorAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: str
}
return (
<div className="row is-center">
<StyledErrorAlert className="col-10 is-vertical-align row">
<StyledErrorAlert className="col-12 is-vertical-align row">
<InfoIcon color="var(--failed-color)" />
<TextContainer className="col-10">
{text}
Expand Down
34 changes: 34 additions & 0 deletions alm/src/components/commons/WarningAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'
import styled from 'styled-components'
import { InfoIcon } from './InfoIcon'
import { CloseIcon } from './CloseIcon'

const StyledErrorAlert = styled.div`
border: 1px solid var(--warning-color);
border-radius: 4px;
margin-bottom: 20px;
padding-top: 10px;
`

const CloseIconContainer = styled.div`
cursor: pointer;
`

const TextContainer = styled.div`
white-space: pre-wrap;
flex-direction: column;
`

export const WarningAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
return (
<div className="row is-center">
<StyledErrorAlert className="col-12 is-vertical-align row">
<InfoIcon color="var(--warning-color)" />
<TextContainer className="col-10">{error}</TextContainer>
<CloseIconContainer className="col-1 is-vertical-align is-center" onClick={onClick}>
<CloseIcon color="var(--warning-color)" />
</CloseIconContainer>
</StyledErrorAlert>
</div>
)
}
3 changes: 2 additions & 1 deletion alm/src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export const CONFIRMATIONS_STATUS = {
}

export const VALIDATOR_CONFIRMATION_STATUS = {
SUCCESS: 'Success',
SUCCESS: 'Confirmed',
EXECUTION_SUCCESS: 'Executed',
FAILED: 'Failed',
PENDING: 'Pending',
WAITING: 'Waiting',
Expand Down
5 changes: 4 additions & 1 deletion alm/src/hooks/useMessageConfirmations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,10 @@ export const useMessageConfirmations = ({
// Sets the message status based in the collected information
useEffect(
() => {
if (executionData.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS && existsConfirmation(confirmations)) {
if (
executionData.status === VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS &&
existsConfirmation(confirmations)
) {
const newStatus = executionData.executionResult
? CONFIRMATIONS_STATUS.SUCCESS
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
Expand Down
Loading