Compare commits
2 Commits
test-molec
...
feature/am
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5490b8b029 | ||
|
|
3f93fef016 |
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
|||||||
- name: Rebuild and push updated images
|
- name: Rebuild and push updated images
|
||||||
run: |
|
run: |
|
||||||
function check_if_image_exists() {
|
function check_if_image_exists() {
|
||||||
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
updated=()
|
updated=()
|
||||||
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
if ! check_if_image_exists e2e ${E2E_TAG}; then updated+=("e2e"); fi
|
||||||
@@ -104,7 +104,7 @@ jobs:
|
|||||||
- name: Rebuild and push molecule runner e2e image
|
- name: Rebuild and push molecule runner e2e image
|
||||||
run: |
|
run: |
|
||||||
function check_if_image_exists() {
|
function check_if_image_exists() {
|
||||||
curl -fsSlL "https://${{ github.actor }}:${{ github.token }}@${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
curl -fsSlL -H 'Authorization: bearer ${{ github.token }}' "https://${DOCKER_REGISTRY}/v2/${DOCKER_REPO}/tokenbridge-e2e-$1/manifests/$2" > /dev/null
|
||||||
}
|
}
|
||||||
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
if check_if_image_exists molecule_runner ${MOLECULE_RUNNER_TAG}; then
|
||||||
echo "Image already exists"
|
echo "Image already exists"
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
- name: Login to docker registry
|
- name: Login to docker registry
|
||||||
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
run: docker login ${DOCKER_REGISTRY} -u ${{ github.actor }} -p ${{ github.token }}
|
||||||
- name: Deploy contracts
|
- name: Deploy contracts
|
||||||
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy generate-amb-tx blocks
|
run: ${{ steps.cache-repo.outputs.cache-hit }} && e2e-commons/up.sh deploy blocks
|
||||||
- name: Pull e2e oracle image
|
- name: Pull e2e oracle image
|
||||||
run: |
|
run: |
|
||||||
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle-amb
|
docker-compose -f ./e2e-commons/docker-compose.yml pull oracle-amb
|
||||||
|
|||||||
@@ -52,9 +52,6 @@ ORACLE_SHUTDOWN_CONTRACT_ADDRESS | Optional contract address in the side chain a
|
|||||||
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
ORACLE_SHUTDOWN_CONTRACT_METHOD | Method signature to be used in the side chain to identify the current shutdown status. Method should return boolean. Default value is `isShutdown()`. | `function signature`
|
||||||
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
|
ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Foreign chain. Infinite, if not provided. | `integer`
|
||||||
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
|
ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT | Max length for the block range used in `eth_getLogs` requests for polling contract events for the Home chain. Infinite, if not provided. | `integer`
|
||||||
ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trigger RPC fallback to the next URL from the list (or a retry in case of a single RPC URL). Default is `-32603,-32002,-32005`. Should be a comma-separated list of negative integers. | `string`
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH | Path to the keystore v3 json file with the encrypted validator key. | `string`
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD | Password from the provided keystore file, oracle won't startup properly, if the provided password is invalid | `string`
|
|
||||||
|
|
||||||
|
|
||||||
## Monitor configuration
|
## Monitor configuration
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
|||||||
COPY commons/package.json ./commons/
|
COPY commons/package.json ./commons/
|
||||||
COPY oracle-e2e/package.json ./oracle-e2e/
|
COPY oracle-e2e/package.json ./oracle-e2e/
|
||||||
COPY monitor-e2e/package.json ./monitor-e2e/
|
COPY monitor-e2e/package.json ./monitor-e2e/
|
||||||
COPY oracle/src/utils/constants.js ./oracle/src/utils/constants.js
|
|
||||||
|
|
||||||
COPY yarn.lock .
|
COPY yarn.lock .
|
||||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
|
|
||||||
../e2e-commons/up.sh deploy generate-amb-tx blocks alm alm-e2e
|
../e2e-commons/up.sh deploy blocks alm alm-e2e
|
||||||
|
|
||||||
# run oracle amb e2e tests to generate transactions for alm
|
# run oracle amb e2e tests to generate transactions for alm
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm
|
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run alm
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ jest.setTimeout(60000)
|
|||||||
const statusText = 'Success'
|
const statusText = 'Success'
|
||||||
const statusSelector = 'label[data-id="status"]'
|
const statusSelector = 'label[data-id="status"]'
|
||||||
|
|
||||||
const homeToForeignTxURL = 'http://localhost:3004/77/0x295efbe6ae98937ef35d939376c9bd752b4dc6f6899a9d5ddd6a57cea3d76c89'
|
const homeToForeignTxURL = 'http://localhost:3004/77/0xbc83d43bdc675a615a2b820e43e52d25857aa5fdd77acf2dd92cd247af2c693c'
|
||||||
const foreignToHomeTxURL = 'http://localhost:3004/42/0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd'
|
const foreignToHomeTxURL = 'http://localhost:3004/42/0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6'
|
||||||
|
|
||||||
describe('ALM', () => {
|
describe('ALM', () => {
|
||||||
let browser
|
let browser
|
||||||
|
|||||||
@@ -123,24 +123,6 @@ const abi: AbiItem[] = [
|
|||||||
stateMutability: 'nonpayable',
|
stateMutability: 'nonpayable',
|
||||||
type: 'function'
|
type: 'function'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
constant: false,
|
|
||||||
inputs: [
|
|
||||||
{
|
|
||||||
name: '_data',
|
|
||||||
type: 'bytes'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '_signatures',
|
|
||||||
type: 'bytes'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
name: 'safeExecuteSignaturesWithAutoGasLimit',
|
|
||||||
outputs: [],
|
|
||||||
payable: false,
|
|
||||||
stateMutability: 'nonpayable',
|
|
||||||
type: 'function'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
constant: true,
|
constant: true,
|
||||||
inputs: [
|
inputs: [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React from 'react'
|
||||||
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
||||||
import { useWindowWidth } from '@react-hook/window-size'
|
import { useWindowWidth } from '@react-hook/window-size'
|
||||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
||||||
@@ -9,7 +9,6 @@ import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
|||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||||
import { ManualExecutionButton } from './ManualExecutionButton'
|
import { ManualExecutionButton } from './ManualExecutionButton'
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
|
||||||
|
|
||||||
const StyledExecutionConfirmation = styled.div`
|
const StyledExecutionConfirmation = styled.div`
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
@@ -34,8 +33,6 @@ export const ExecutionConfirmation = ({
|
|||||||
executionEventsFetched,
|
executionEventsFetched,
|
||||||
setPendingExecution
|
setPendingExecution
|
||||||
}: ExecutionConfirmationParams) => {
|
}: ExecutionConfirmationParams) => {
|
||||||
const { foreign } = useStateProvider()
|
|
||||||
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
|
|
||||||
const availableManualExecution =
|
const availableManualExecution =
|
||||||
!isHome &&
|
!isHome &&
|
||||||
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
|
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
|
||||||
@@ -51,22 +48,6 @@ export const ExecutionConfirmation = ({
|
|||||||
const formattedValidator =
|
const formattedValidator =
|
||||||
windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator
|
windowWidth < 850 && executionData.validator ? formatTxHash(executionData.validator) : executionData.validator
|
||||||
|
|
||||||
useEffect(
|
|
||||||
() => {
|
|
||||||
if (!availableManualExecution || !foreign.bridgeContract) return
|
|
||||||
|
|
||||||
const p = foreign.bridgeContract.methods.getBridgeInterfacesVersion().call()
|
|
||||||
p.then(({ major, minor }: any) => {
|
|
||||||
major = parseInt(major, 10)
|
|
||||||
minor = parseInt(minor, 10)
|
|
||||||
if (major < 5 || (major === 5 && minor < 7)) return
|
|
||||||
|
|
||||||
setSafeExecutionAvailable(true)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[availableManualExecution, foreign.bridgeContract]
|
|
||||||
)
|
|
||||||
|
|
||||||
const getExecutionStatusElement = (validatorStatus = '') => {
|
const getExecutionStatusElement = (validatorStatus = '') => {
|
||||||
switch (validatorStatus) {
|
switch (validatorStatus) {
|
||||||
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
|
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
|
||||||
@@ -124,7 +105,6 @@ export const ExecutionConfirmation = ({
|
|||||||
{availableManualExecution && (
|
{availableManualExecution && (
|
||||||
<td>
|
<td>
|
||||||
<ManualExecutionButton
|
<ManualExecutionButton
|
||||||
safeExecutionAvailable={safeExecutionAvailable}
|
|
||||||
messageData={messageData}
|
messageData={messageData}
|
||||||
setExecutionData={setExecutionData}
|
setExecutionData={setExecutionData}
|
||||||
signatureCollected={signatureCollected as string[]}
|
signatureCollected={signatureCollected as string[]}
|
||||||
|
|||||||
@@ -15,19 +15,16 @@ import { signatureToVRS, packSignatures } from '../utils/signatures'
|
|||||||
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
|
|
||||||
const ActionButton = styled.button`
|
const StyledButton = styled.button`
|
||||||
color: var(--button-color);
|
color: var(--button-color);
|
||||||
border-color: var(--font-color);
|
border-color: var(--font-color);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
min-width: 120px;
|
|
||||||
padding: 1rem;
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: var(--button-color);
|
outline: var(--button-color);
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
interface ManualExecutionButtonParams {
|
interface ManualExecutionButtonParams {
|
||||||
safeExecutionAvailable: boolean
|
|
||||||
messageData: string
|
messageData: string
|
||||||
setExecutionData: Function
|
setExecutionData: Function
|
||||||
signatureCollected: string[]
|
signatureCollected: string[]
|
||||||
@@ -35,7 +32,6 @@ interface ManualExecutionButtonParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ManualExecutionButton = ({
|
export const ManualExecutionButton = ({
|
||||||
safeExecutionAvailable,
|
|
||||||
messageData,
|
messageData,
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
signatureCollected,
|
signatureCollected,
|
||||||
@@ -44,8 +40,6 @@ export const ManualExecutionButton = ({
|
|||||||
const { foreign, setError } = useStateProvider()
|
const { foreign, setError } = useStateProvider()
|
||||||
const { library, activate, account, active } = useWeb3React()
|
const { library, activate, account, active } = useWeb3React()
|
||||||
const [manualExecution, setManualExecution] = useState(false)
|
const [manualExecution, setManualExecution] = useState(false)
|
||||||
const [allowFailures, setAllowFailures] = useState(false)
|
|
||||||
const notReady = !foreign.bridgeContract || !signatureCollected || !signatureCollected.length
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
@@ -78,11 +72,7 @@ export const ManualExecutionButton = ({
|
|||||||
const signatures = packSignatures(signatureCollected.map(signatureToVRS))
|
const signatures = packSignatures(signatureCollected.map(signatureToVRS))
|
||||||
const messageId = messageData.slice(0, 66)
|
const messageId = messageData.slice(0, 66)
|
||||||
const bridge = foreign.bridgeContract
|
const bridge = foreign.bridgeContract
|
||||||
const executeMethod =
|
const data = bridge.methods.executeSignatures(messageData, signatures).encodeABI()
|
||||||
safeExecutionAvailable && !allowFailures
|
|
||||||
? bridge.methods.safeExecuteSignaturesWithAutoGasLimit
|
|
||||||
: bridge.methods.executeSignatures
|
|
||||||
const data = executeMethod(messageData, signatures).encodeABI()
|
|
||||||
setManualExecution(false)
|
setManualExecution(false)
|
||||||
|
|
||||||
library.eth
|
library.eth
|
||||||
@@ -142,35 +132,15 @@ export const ManualExecutionButton = ({
|
|||||||
messageData,
|
messageData,
|
||||||
signatureCollected,
|
signatureCollected,
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
setPendingExecution,
|
setPendingExecution
|
||||||
safeExecutionAvailable,
|
|
||||||
allowFailures
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<div className="is-center">
|
<div className="is-center">
|
||||||
<ActionButton disabled={notReady} className="button outline" onClick={() => setManualExecution(true)}>
|
<StyledButton className="button outline" onClick={() => setManualExecution(true)}>
|
||||||
Execute
|
Execute
|
||||||
</ActionButton>
|
</StyledButton>
|
||||||
</div>
|
|
||||||
{safeExecutionAvailable && (
|
|
||||||
<div
|
|
||||||
title="Allow executed message to fail and record its failure on-chain without reverting the whole transaction.
|
|
||||||
Use fixed gas limit for execution."
|
|
||||||
className="is-center"
|
|
||||||
style={{ paddingTop: 10 }}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id="allow-failures"
|
|
||||||
checked={allowFailures}
|
|
||||||
onChange={e => setAllowFailures(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<label htmlFor="allow-failures">Unsafe mode</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,14 +86,6 @@ export const getConfirmationsForTx = async (
|
|||||||
setPendingConfirmations(validatorPendingConfirmations.length > 0)
|
setPendingConfirmations(validatorPendingConfirmations.length > 0)
|
||||||
} else {
|
} else {
|
||||||
setPendingConfirmations(false)
|
setPendingConfirmations(false)
|
||||||
if (fromHome) {
|
|
||||||
// fetch collected signatures for possible manual processing
|
|
||||||
setSignatureCollected(
|
|
||||||
await Promise.all(
|
|
||||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const undefinedConfirmations = validatorConfirmations.filter(
|
const undefinedConfirmations = validatorConfirmations.filter(
|
||||||
@@ -123,6 +115,15 @@ export const getConfirmationsForTx = async (
|
|||||||
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
||||||
}))
|
}))
|
||||||
updateConfirmations(notRequiredConfirmations)
|
updateConfirmations(notRequiredConfirmations)
|
||||||
|
|
||||||
|
if (fromHome) {
|
||||||
|
// fetch collected signatures for possible manual processing
|
||||||
|
setSignatureCollected(
|
||||||
|
await Promise.all(
|
||||||
|
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get transactions from success signatures
|
// get transactions from success signatures
|
||||||
|
|||||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
|
const HOME_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/HomeBridgeErcToNative').abi
|
||||||
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/XDaiForeignBridge.json').abi
|
const FOREIGN_ERC_TO_NATIVE_ABI = require('../contracts/build/contracts/ForeignBridgeErcToNative').abi
|
||||||
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
const ERC20_ABI = require('../contracts/build/contracts/ERC20').abi
|
||||||
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi
|
const BLOCK_REWARD_ABI = require('../contracts/build/contracts/BlockRewardMock').abi
|
||||||
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
const BRIDGE_VALIDATORS_ABI = require('../contracts/build/contracts/BridgeValidators').abi
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const { soliditySha3 } = require('web3-utils')
|
|
||||||
|
|
||||||
function strip0x(input) {
|
function strip0x(input) {
|
||||||
return input.replace(/^0x/, '')
|
return input.replace(/^0x/, '')
|
||||||
}
|
}
|
||||||
@@ -41,35 +39,8 @@ const normalizeAMBMessageEvent = e => {
|
|||||||
return parseAMBMessage(msgData)
|
return parseAMBMessage(msgData)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ambInformationSignatures = [
|
|
||||||
'eth_call(address,bytes)',
|
|
||||||
'eth_call(address,bytes,uint256)',
|
|
||||||
'eth_call(address,address,uint256,bytes)',
|
|
||||||
'eth_blockNumber()',
|
|
||||||
'eth_getBlockByNumber()',
|
|
||||||
'eth_getBlockByNumber(uint256)',
|
|
||||||
'eth_getBlockByHash(bytes32)',
|
|
||||||
'eth_getBalance(address)',
|
|
||||||
'eth_getBalance(address,uint256)',
|
|
||||||
'eth_getTransactionCount(address)',
|
|
||||||
'eth_getTransactionCount(address,uint256)',
|
|
||||||
'eth_getTransactionByHash(bytes32)',
|
|
||||||
'eth_getTransactionReceipt(bytes32)',
|
|
||||||
'eth_getStorageAt(address,bytes32)',
|
|
||||||
'eth_getStorageAt(address,bytes32,uint256)'
|
|
||||||
]
|
|
||||||
const ambInformationSelectors = Object.fromEntries(ambInformationSignatures.map(sig => [soliditySha3(sig), sig]))
|
|
||||||
const normalizeAMBInfoRequest = e => ({
|
|
||||||
messageId: e.returnValues.messageId,
|
|
||||||
sender: e.returnValues.sender,
|
|
||||||
requestSelector: ambInformationSelectors[e.returnValues.requestSelector] || 'unknown',
|
|
||||||
data: e.returnValues.data
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
strip0x,
|
strip0x,
|
||||||
parseAMBMessage,
|
parseAMBMessage,
|
||||||
normalizeAMBMessageEvent,
|
normalizeAMBMessageEvent
|
||||||
ambInformationSignatures,
|
|
||||||
normalizeAMBInfoRequest
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gas-price-oracle": "^0.1.5",
|
"gas-price-oracle": "^0.1.5",
|
||||||
"web3-utils": "^1.3.0",
|
"web3-utils": "^1.3.0"
|
||||||
"node-fetch": "^2.1.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bn-chai": "^1.0.1",
|
"bn-chai": "^1.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const { toWei, toBN, BN } = require('web3-utils')
|
const { toWei, toBN, BN } = require('web3-utils')
|
||||||
const { GasPriceOracle } = require('gas-price-oracle')
|
const { GasPriceOracle } = require('gas-price-oracle')
|
||||||
const fetch = require('node-fetch')
|
|
||||||
const { BRIDGE_MODES } = require('./constants')
|
const { BRIDGE_MODES } = require('./constants')
|
||||||
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
|
const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
|
||||||
|
|
||||||
@@ -179,16 +178,17 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
|
|||||||
return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
|
return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const gasPriceFromSupplier = async (url, options = {}) => {
|
// fetchFn has to be supplied (instead of just url to oracle),
|
||||||
|
// because this utility function is shared between Browser and Node,
|
||||||
|
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
|
||||||
|
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
|
||||||
try {
|
try {
|
||||||
let json
|
let json
|
||||||
if (url === 'gas-price-oracle') {
|
if (fetchFn) {
|
||||||
json = await gasPriceOracle.fetchGasPricesOffChain()
|
const response = await fetchFn()
|
||||||
} else if (url) {
|
|
||||||
const response = await fetch(url, { timeout: 2000 })
|
|
||||||
json = await response.json()
|
json = await response.json()
|
||||||
} else {
|
} else {
|
||||||
return null
|
json = await gasPriceOracle.fetchGasPricesOffChain()
|
||||||
}
|
}
|
||||||
const oracleGasPrice = json[options.speedType]
|
const oracleGasPrice = json[options.speedType]
|
||||||
|
|
||||||
|
|||||||
Submodule contracts updated: 908a481079...c2575aa268
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.7
|
FROM python:3.7-stretch
|
||||||
RUN curl -fsSL https://get.docker.com | sh
|
RUN curl -fsSL https://get.docker.com | sh
|
||||||
RUN pip3 install docker molecule[docker,ansible] pytest pytest-testinfra flake8
|
RUN pip3 install docker molecule==2.22rc1 molecule[docker] flake8
|
||||||
WORKDIR mono/deployment-e2e
|
WORKDIR mono/deployment-e2e
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ dependency:
|
|||||||
name: galaxy
|
name: galaxy
|
||||||
driver:
|
driver:
|
||||||
name: docker
|
name: docker
|
||||||
|
lint:
|
||||||
|
name: yamllint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
config-data:
|
||||||
|
ignore: ../../hosts.yml
|
||||||
platforms:
|
platforms:
|
||||||
- name: monitor-host
|
- name: monitor-host
|
||||||
groups:
|
groups:
|
||||||
@@ -16,6 +22,11 @@ platforms:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
provisioner:
|
provisioner:
|
||||||
name: ansible
|
name: ansible
|
||||||
|
lint:
|
||||||
|
name: ansible-lint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
r: ["bug"]
|
||||||
playbooks:
|
playbooks:
|
||||||
prepare: ../prepare.yml
|
prepare: ../prepare.yml
|
||||||
converge: ./converge.yml
|
converge: ./converge.yml
|
||||||
@@ -26,11 +37,14 @@ provisioner:
|
|||||||
syslog_server_port: "udp://127.0.0.1:514"
|
syslog_server_port: "udp://127.0.0.1:514"
|
||||||
verifier:
|
verifier:
|
||||||
name: testinfra
|
name: testinfra
|
||||||
|
lint:
|
||||||
|
name: flake8
|
||||||
additional_files_or_dirs:
|
additional_files_or_dirs:
|
||||||
- ../../tests/*
|
- ../../tests/*
|
||||||
scenario:
|
scenario:
|
||||||
name: monitor
|
name: monitor
|
||||||
test_sequence:
|
test_sequence:
|
||||||
|
- lint
|
||||||
- cleanup
|
- cleanup
|
||||||
- destroy
|
- destroy
|
||||||
- dependency
|
- dependency
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ dependency:
|
|||||||
name: galaxy
|
name: galaxy
|
||||||
driver:
|
driver:
|
||||||
name: docker
|
name: docker
|
||||||
|
lint:
|
||||||
|
name: yamllint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
config-data:
|
||||||
|
ignore: ../../hosts.yml
|
||||||
platforms:
|
platforms:
|
||||||
- name: multiple-host
|
- name: multiple-host
|
||||||
groups:
|
groups:
|
||||||
@@ -17,6 +23,11 @@ platforms:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
provisioner:
|
provisioner:
|
||||||
name: ansible
|
name: ansible
|
||||||
|
lint:
|
||||||
|
name: ansible-lint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
r: ["bug"]
|
||||||
playbooks:
|
playbooks:
|
||||||
prepare: ../prepare.yml
|
prepare: ../prepare.yml
|
||||||
converge: ../monitor/converge.yml
|
converge: ../monitor/converge.yml
|
||||||
@@ -28,11 +39,14 @@ provisioner:
|
|||||||
syslog_server_port: "udp://127.0.0.1:514"
|
syslog_server_port: "udp://127.0.0.1:514"
|
||||||
verifier:
|
verifier:
|
||||||
name: testinfra
|
name: testinfra
|
||||||
|
lint:
|
||||||
|
name: flake8
|
||||||
additional_files_or_dirs:
|
additional_files_or_dirs:
|
||||||
- ../../tests/*
|
- ../../tests/*
|
||||||
scenario:
|
scenario:
|
||||||
name: multiple
|
name: multiple
|
||||||
test_sequence:
|
test_sequence:
|
||||||
|
- lint
|
||||||
- cleanup
|
- cleanup
|
||||||
- destroy
|
- destroy
|
||||||
- dependency
|
- dependency
|
||||||
|
|||||||
@@ -3,12 +3,18 @@ dependency:
|
|||||||
name: galaxy
|
name: galaxy
|
||||||
driver:
|
driver:
|
||||||
name: docker
|
name: docker
|
||||||
|
lint:
|
||||||
|
name: yamllint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
config-data:
|
||||||
|
ignore: ../../hosts.yml
|
||||||
platforms:
|
platforms:
|
||||||
- name: oracle-host
|
- name: oracle-host
|
||||||
groups:
|
groups:
|
||||||
- example
|
- example
|
||||||
children:
|
children:
|
||||||
- oracle_swarm
|
- oracle
|
||||||
image: ubuntu:16.04
|
image: ubuntu:16.04
|
||||||
privileged: true
|
privileged: true
|
||||||
network_mode: host
|
network_mode: host
|
||||||
@@ -16,22 +22,29 @@ platforms:
|
|||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
provisioner:
|
provisioner:
|
||||||
name: ansible
|
name: ansible
|
||||||
|
lint:
|
||||||
|
name: ansible-lint
|
||||||
|
enabled: True
|
||||||
|
options:
|
||||||
|
r: ["bug"]
|
||||||
playbooks:
|
playbooks:
|
||||||
prepare: ../prepare.yml
|
prepare: ../prepare.yml
|
||||||
converge: ../../../deployment/site.yml
|
converge: ../../../deployment/site.yml
|
||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-host:
|
oracle-host:
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH: "../../../e2e-commons/keystore.json"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "6c48435bd464a53ed66ed62127c4dba8af75cf1a99a8ebe2680599948fbfbc6d"
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678"
|
|
||||||
syslog_server_port: "udp://127.0.0.1:514"
|
syslog_server_port: "udp://127.0.0.1:514"
|
||||||
verifier:
|
verifier:
|
||||||
name: testinfra
|
name: testinfra
|
||||||
|
lint:
|
||||||
|
name: flake8
|
||||||
additional_files_or_dirs:
|
additional_files_or_dirs:
|
||||||
- ../../tests/*
|
- ../../tests/*
|
||||||
scenario:
|
scenario:
|
||||||
name: oracle
|
name: oracle
|
||||||
test_sequence:
|
test_sequence:
|
||||||
|
- lint
|
||||||
- cleanup
|
- cleanup
|
||||||
- destroy
|
- destroy
|
||||||
- dependency
|
- dependency
|
||||||
|
|||||||
@@ -3,21 +3,22 @@ import pytest
|
|||||||
import testinfra.utils.ansible_runner
|
import testinfra.utils.ansible_runner
|
||||||
|
|
||||||
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
|
||||||
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle_swarm')
|
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('oracle')
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("name", [
|
@pytest.mark.parametrize("name", [
|
||||||
("oracle_rabbit"),
|
("oracle_rabbit_1"),
|
||||||
("oracle_redis"),
|
("oracle_redis_1"),
|
||||||
("oracle_bridge_request"),
|
("oracle_bridge_request_1"),
|
||||||
("oracle_bridge_collected"),
|
("oracle_bridge_collected_1"),
|
||||||
("oracle_bridge_affirmation"),
|
("oracle_bridge_affirmation_1"),
|
||||||
("oracle_bridge_senderhome"),
|
("oracle_bridge_senderhome_1"),
|
||||||
("oracle_bridge_senderforeign"),
|
("oracle_bridge_senderforeign_1"),
|
||||||
("oracle_bridge_shutdown"),
|
("oracle_bridge_shutdown_1"),
|
||||||
])
|
])
|
||||||
def test_docker_containers(host, name):
|
def test_docker_containers(host, name):
|
||||||
assert host.docker(name) is not None
|
container = host.docker(name)
|
||||||
|
assert container.is_running
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("service", [
|
@pytest.mark.parametrize("service", [
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ platforms:
|
|||||||
- ultimate
|
- ultimate
|
||||||
- amb
|
- amb
|
||||||
children:
|
children:
|
||||||
- oracle_swarm
|
- oracle
|
||||||
image: ubuntu:16.04
|
image: ubuntu:16.04
|
||||||
privileged: true
|
privileged: true
|
||||||
network_mode: host
|
network_mode: host
|
||||||
@@ -21,10 +21,12 @@ provisioner:
|
|||||||
inventory:
|
inventory:
|
||||||
host_vars:
|
host_vars:
|
||||||
oracle-amb-host:
|
oracle-amb-host:
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH: "../../../e2e-commons/keystore_ultimate.json"
|
ORACLE_VALIDATOR_ADDRESS: "0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
||||||
verifier:
|
verifier:
|
||||||
name: testinfra
|
name: testinfra
|
||||||
|
lint:
|
||||||
|
name: flake8
|
||||||
scenario:
|
scenario:
|
||||||
name: ultimate-amb
|
name: ultimate-amb
|
||||||
test_sequence:
|
test_sequence:
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ provisioner:
|
|||||||
ORACLE_FOREIGN_START_BLOCK: 1
|
ORACLE_FOREIGN_START_BLOCK: 1
|
||||||
verifier:
|
verifier:
|
||||||
name: testinfra
|
name: testinfra
|
||||||
|
lint:
|
||||||
|
name: flake8
|
||||||
scenario:
|
scenario:
|
||||||
name: ultimate-erc-to-native
|
name: ultimate-erc-to-native
|
||||||
test_sequence:
|
test_sequence:
|
||||||
|
|||||||
@@ -7,13 +7,6 @@ sokol-kovan:
|
|||||||
ansible_user: ubuntu
|
ansible_user: ubuntu
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
#syslog_server_port: "udp://127.0.0.1:514"
|
#syslog_server_port: "udp://127.0.0.1:514"
|
||||||
oracle_swarm:
|
|
||||||
hosts:
|
|
||||||
127.0.0.1:
|
|
||||||
ansible_user: ubuntu
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH: "/path/to/keystore.json"
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD: "12345678"
|
|
||||||
#syslog_server_port: "udp://127.0.0.1:514"
|
|
||||||
monitor:
|
monitor:
|
||||||
hosts:
|
hosts:
|
||||||
127.0.0.1:
|
127.0.0.1:
|
||||||
|
|||||||
4
deployment/requirements.txt
Normal file
4
deployment/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# pre-release because it contains "CI Fixes for ansible 2.8"
|
||||||
|
molecule==2.22rc1
|
||||||
|
docker
|
||||||
|
flake8
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"live-restore": false,
|
"live-restore": true,
|
||||||
"no-new-privileges": true
|
"no-new-privileges": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
owner: "root"
|
owner: "root"
|
||||||
group: "root"
|
group: "root"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
when: skip_compose is undefined
|
|
||||||
|
|
||||||
- name: Upgrade pip version
|
- name: Upgrade pip version
|
||||||
shell: pip3 install --upgrade pip==19.3.1
|
shell: pip3 install --upgrade pip==19.3.1
|
||||||
@@ -46,9 +45,6 @@
|
|||||||
group: docker
|
group: docker
|
||||||
createhome: yes
|
createhome: yes
|
||||||
|
|
||||||
- name: reset ssh connection to allow user changes to affect ansible user
|
|
||||||
meta: reset_connection
|
|
||||||
|
|
||||||
- name: Install auditd
|
- name: Install auditd
|
||||||
apt:
|
apt:
|
||||||
name: auditd
|
name: auditd
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/var/log/docker/*/docker.log {
|
/var/log/docker/*/docker.log {
|
||||||
rotate 5
|
rotate 5
|
||||||
size 100M
|
size 1G
|
||||||
compress
|
compress
|
||||||
missingok
|
missingok
|
||||||
delaycompress
|
delaycompress
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
/var/log/docker/*.log {
|
/var/log/docker/*.log {
|
||||||
rotate 5
|
rotate 5
|
||||||
size 100M
|
size 1G
|
||||||
compress
|
compress
|
||||||
missingok
|
missingok
|
||||||
delaycompress
|
delaycompress
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
loop_control:
|
loop_control:
|
||||||
loop_var: file
|
loop_var: file
|
||||||
|
|
||||||
- name: Set the oracle's containers local logs configuration file
|
- name: Set the local container logs configuration file
|
||||||
template:
|
template:
|
||||||
src: 31-oracle-docker.conf.j2
|
src: 31-oracle-docker.conf.j2
|
||||||
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
||||||
@@ -15,22 +15,6 @@
|
|||||||
group: root
|
group: root
|
||||||
mode: 0644
|
mode: 0644
|
||||||
|
|
||||||
- name: Set the redis container local logs configuration file
|
|
||||||
template:
|
|
||||||
src: 32-redis-docker.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/32-redis-docker.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Set the rabbit MQ container local logs configuration file
|
|
||||||
template:
|
|
||||||
src: 33-rabbit-docker.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/33-rabbit-docker.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Set the log configuration file to send container logs to remote server
|
- name: Set the log configuration file to send container logs to remote server
|
||||||
template:
|
template:
|
||||||
src: 36-oracle-remote-logging.conf.j2
|
src: 36-oracle-remote-logging.conf.j2
|
||||||
|
|||||||
@@ -27,6 +27,17 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
ORACLE_VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}"
|
ORACLE_VALIDATOR_ADDRESS: "{{ VADDRESS.stdout }}"
|
||||||
|
|
||||||
|
- name: Get foreign erc type
|
||||||
|
become_user: "{{ compose_service_user }}"
|
||||||
|
shell: docker-compose run --rm --entrypoint "node scripts/initialChecks.js" bridge_affirmation
|
||||||
|
args:
|
||||||
|
chdir: "{{ bridge_path }}/oracle"
|
||||||
|
register: ERCTYPE
|
||||||
|
|
||||||
|
- name: Set FOREIGN_ERC_TYPE variable
|
||||||
|
set_fact:
|
||||||
|
FOREIGN_ERC_TYPE: "{{ (ERCTYPE.stdout).foreignERC | default('') }}"
|
||||||
|
|
||||||
- name: Extend docker compose file for erc to native
|
- name: Extend docker compose file for erc to native
|
||||||
set_fact: composefileoverride="-f docker-compose-transfer.yml"
|
set_fact: composefileoverride="-f docker-compose-transfer.yml"
|
||||||
when: ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE"
|
when: ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE"
|
||||||
|
|||||||
@@ -11,16 +11,9 @@ ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
|
|||||||
|
|
||||||
## Foreign contract
|
## Foreign contract
|
||||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
||||||
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
|
|
||||||
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
|
|
||||||
{% endif %}
|
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
||||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
||||||
|
|
||||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
|
||||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Gasprice
|
## Gasprice
|
||||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
||||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
||||||
@@ -54,28 +47,8 @@ COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
|||||||
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
||||||
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
||||||
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
||||||
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %}
|
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
||||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }}
|
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Emergency shutdown configuration
|
|
||||||
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
|
|
||||||
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
$FileCreateMode 0644
|
|
||||||
template(name="DockerLogFileName_Redis" type="list") {
|
|
||||||
constant(value="/var/log/docker/")
|
|
||||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
|
|
||||||
constant(value="/docker.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if $programname contains 'oracle' and $programname contains 'redis' then \
|
|
||||||
?DockerLogFileName_Redis
|
|
||||||
|
|
||||||
$FileCreateMode 0600
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
$FileCreateMode 0644
|
|
||||||
template(name="DockerLogFileName_Rabbit" type="list") {
|
|
||||||
constant(value="/var/log/docker/")
|
|
||||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
|
|
||||||
constant(value="/docker.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if $programname contains 'oracle' and $programname contains 'rabbit' then \
|
|
||||||
?DockerLogFileName_Rabbit
|
|
||||||
|
|
||||||
$FileCreateMode 0600
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
bridge_path: "/home/{{ compose_service_user }}/bridge"
|
|
||||||
bridge_data_path: "/home/{{ compose_service_user }}/bridge_data"
|
|
||||||
ORACLE_ALLOW_HTTP_FOR_RPC: no
|
|
||||||
ORACLE_QUEUE_URL: amqp://rabbit
|
|
||||||
ORACLE_REDIS_URL: redis://redis
|
|
||||||
keyfile_path: "/root/.key"
|
|
||||||
keystore_path: "/root/.keystore.json"
|
|
||||||
oracle_image: poanetwork/tokenbridge-oracle:latest
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
dependencies:
|
|
||||||
- { role: common, skip_repo: true, skip_compose: true }
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Pull the containers images
|
|
||||||
community.docker.docker_image:
|
|
||||||
name: "{{ oracle_image }}"
|
|
||||||
source: pull
|
|
||||||
when: skip_pull is undefined
|
|
||||||
vars:
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Set the oracle's containers local logs configuration file
|
|
||||||
template:
|
|
||||||
src: 31-oracle-docker.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/31-oracle-docker.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Set the redis container local logs configuration file
|
|
||||||
template:
|
|
||||||
src: 32-redis-docker.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/32-redis-docker.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Set the rabbit MQ container local logs configuration file
|
|
||||||
template:
|
|
||||||
src: 33-rabbit-docker.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/33-rabbit-docker.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Set the log configuration file to send container logs to remote server
|
|
||||||
template:
|
|
||||||
src: 36-oracle-remote-logging.conf.j2
|
|
||||||
dest: /etc/rsyslog.d/36-oracle-remote-logging.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
when: syslog_server_port is defined
|
|
||||||
|
|
||||||
- name: Discarding unwanted messages in rsyslog
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/rsyslog.conf
|
|
||||||
insertbefore: "# Where to place spool and state files"
|
|
||||||
marker: "#{mark} add string to discarding unwanted messages"
|
|
||||||
content: ':msg, contains, "ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY" ~'
|
|
||||||
notify: restart rsyslog
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
- include_tasks: pre_config.yml
|
|
||||||
- include_tasks: logging.yml
|
|
||||||
- include_tasks: jumpbox.yml
|
|
||||||
- include_tasks: post_config.yml
|
|
||||||
- include_tasks: servinstall.yml
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Get blocks
|
|
||||||
become_user: "{{ compose_service_user }}"
|
|
||||||
shell: docker run --env-file .env --rm {{ oracle_image }} scripts/getValidatorStartBlocks.js
|
|
||||||
args:
|
|
||||||
chdir: "{{ bridge_path }}/oracle"
|
|
||||||
register: BLOCKS
|
|
||||||
when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined)
|
|
||||||
|
|
||||||
- name: Write blocks
|
|
||||||
blockinfile:
|
|
||||||
path: "{{ bridge_path }}/oracle/.env"
|
|
||||||
marker: "## {mark} Calculated by scripts/getValidatorStartBlocks.js"
|
|
||||||
block: |
|
|
||||||
ORACLE_HOME_START_BLOCK={{ (BLOCKS.stdout | from_json).homeStartBlock }}
|
|
||||||
ORACLE_FOREIGN_START_BLOCK={{ (BLOCKS.stdout | from_json).foreignStartBlock }}
|
|
||||||
when: (ORACLE_HOME_START_BLOCK is not defined) or (ORACLE_FOREIGN_START_BLOCK is not defined)
|
|
||||||
|
|
||||||
- name: Copy keystore file
|
|
||||||
copy:
|
|
||||||
src: "{{ ORACLE_VALIDATOR_KEYSTORE_PATH }}"
|
|
||||||
dest: "{{ keystore_path }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0600
|
|
||||||
|
|
||||||
- name: Create swarm secret
|
|
||||||
community.docker.docker_secret:
|
|
||||||
name: oracle_keystore
|
|
||||||
state: present
|
|
||||||
data_src: "{{ keystore_path }}"
|
|
||||||
vars:
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
|
|
||||||
- name: Remove unencrypted keystore file
|
|
||||||
file:
|
|
||||||
path: "{{ keystore_path }}"
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Install .key config
|
|
||||||
template:
|
|
||||||
src: key.j2
|
|
||||||
dest: "{{ keyfile_path }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0600
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Init docker swarm
|
|
||||||
community.docker.docker_swarm:
|
|
||||||
state: present
|
|
||||||
autolock_managers: yes
|
|
||||||
listen_addr: 127.0.0.1:2377
|
|
||||||
vars:
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
|
|
||||||
- name: Get unlock token
|
|
||||||
community.docker.docker_swarm_info:
|
|
||||||
unlock_key: yes
|
|
||||||
register: result
|
|
||||||
vars:
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
|
|
||||||
- name: Print unlock token
|
|
||||||
debug:
|
|
||||||
var: result.swarm_unlock_key
|
|
||||||
|
|
||||||
- name: Create oracle directory
|
|
||||||
file:
|
|
||||||
path: "{{ bridge_path }}/oracle"
|
|
||||||
state: directory
|
|
||||||
mode: '0755'
|
|
||||||
|
|
||||||
- name: Create rabbitmq directory
|
|
||||||
file:
|
|
||||||
path: "{{ bridge_data_path }}/{{ item }}"
|
|
||||||
state: directory
|
|
||||||
mode: '0775'
|
|
||||||
loop:
|
|
||||||
- rabbitmq
|
|
||||||
- redis
|
|
||||||
|
|
||||||
- name: Install .env config
|
|
||||||
template:
|
|
||||||
src: .env.j2
|
|
||||||
dest: "{{ bridge_path }}/oracle/.env"
|
|
||||||
owner: "{{ compose_service_user }}"
|
|
||||||
mode: '0640'
|
|
||||||
|
|
||||||
- name: Install docker-compose file
|
|
||||||
template:
|
|
||||||
src: docker-compose.yml.j2
|
|
||||||
dest: "{{ bridge_path }}/oracle/docker-compose.yml"
|
|
||||||
mode: '0755'
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# This role creates a poabridge service which is designed to manage docker-compose bridge deployment.
|
|
||||||
# /etc/init.d/poabridge start, status, stop, restart - does what the services usually do in such cases.
|
|
||||||
---
|
|
||||||
- name: "Set poabridge service"
|
|
||||||
template:
|
|
||||||
src: poabridge.j2
|
|
||||||
dest: "/etc/init.d/poabridge"
|
|
||||||
owner: root
|
|
||||||
mode: 755
|
|
||||||
|
|
||||||
- name: "Enable the service"
|
|
||||||
service:
|
|
||||||
name: "poabridge"
|
|
||||||
state: started
|
|
||||||
enabled: yes
|
|
||||||
use: service
|
|
||||||
|
|
||||||
- name: Start the service
|
|
||||||
shell: service poabridge start
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
## General settings
|
|
||||||
ORACLE_BRIDGE_MODE={{ ORACLE_BRIDGE_MODE }}
|
|
||||||
{% if ORACLE_LOG_LEVEL | default('') != '' %}
|
|
||||||
ORACLE_LOG_LEVEL={{ ORACLE_LOG_LEVEL }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Home contract
|
|
||||||
COMMON_HOME_RPC_URL={{ COMMON_HOME_RPC_URL }}
|
|
||||||
COMMON_HOME_BRIDGE_ADDRESS={{ COMMON_HOME_BRIDGE_ADDRESS }}
|
|
||||||
ORACLE_HOME_RPC_POLLING_INTERVAL={{ ORACLE_HOME_RPC_POLLING_INTERVAL }}
|
|
||||||
|
|
||||||
## Foreign contract
|
|
||||||
COMMON_FOREIGN_RPC_URL={{ COMMON_FOREIGN_RPC_URL }}
|
|
||||||
{% if ORACLE_FOREIGN_ARCHIVE_RPC_URL | default('') != '' %}
|
|
||||||
ORACLE_FOREIGN_ARCHIVE_RPC_URL={{ ORACLE_FOREIGN_ARCHIVE_RPC_URL }}
|
|
||||||
{% endif %}
|
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS={{ COMMON_FOREIGN_BRIDGE_ADDRESS }}
|
|
||||||
ORACLE_FOREIGN_RPC_POLLING_INTERVAL={{ ORACLE_FOREIGN_RPC_POLLING_INTERVAL }}
|
|
||||||
|
|
||||||
{% if ORACLE_TX_REDUNDANCY | default('') != '' %}
|
|
||||||
ORACLE_TX_REDUNDANCY={{ ORACLE_TX_REDUNDANCY }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Gasprice
|
|
||||||
{% if COMMON_HOME_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
|
||||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL={{ COMMON_HOME_GAS_PRICE_SUPPLIER_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if COMMON_HOME_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
|
||||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE={{ COMMON_HOME_GAS_PRICE_SPEED_TYPE }}
|
|
||||||
{% endif %}
|
|
||||||
COMMON_HOME_GAS_PRICE_FALLBACK={{ COMMON_HOME_GAS_PRICE_FALLBACK }}
|
|
||||||
{% if ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if COMMON_HOME_GAS_PRICE_FACTOR | default('') != '' %}
|
|
||||||
COMMON_HOME_GAS_PRICE_FACTOR={{ COMMON_HOME_GAS_PRICE_FACTOR }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | default('') != '' %}
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL={{ COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | default('') != '' %}
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE={{ COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE }}
|
|
||||||
{% endif %}
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK={{ COMMON_FOREIGN_GAS_PRICE_FALLBACK }}
|
|
||||||
{% if ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL={{ ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if COMMON_FOREIGN_GAS_PRICE_FACTOR | default('') != '' %}
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR={{ COMMON_FOREIGN_GAS_PRICE_FACTOR }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Transport configuration
|
|
||||||
ORACLE_ALLOW_HTTP_FOR_RPC={{ "yes" if ORACLE_ALLOW_HTTP_FOR_RPC else "no" }}
|
|
||||||
ORACLE_QUEUE_URL={{ ORACLE_QUEUE_URL }}
|
|
||||||
ORACLE_REDIS_URL={{ ORACLE_REDIS_URL }}
|
|
||||||
{% if ORACLE_FOREIGN_TX_RESEND_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_FOREIGN_TX_RESEND_INTERVAL={{ ORACLE_FOREIGN_TX_RESEND_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_HOME_TX_RESEND_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_HOME_TX_RESEND_INTERVAL={{ ORACLE_HOME_TX_RESEND_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
## Emergency shutdown configuration
|
|
||||||
{% if ORACLE_SHUTDOWN_SERVICE_URL | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_URL={{ ORACLE_SHUTDOWN_SERVICE_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL={{ ORACLE_SHUTDOWN_SERVICE_POLLING_INTERVAL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SIDE_RPC_URL | default('') != '' %}
|
|
||||||
ORACLE_SIDE_RPC_URL={{ ORACLE_SIDE_RPC_URL }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_CONTRACT_ADDRESS | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_ADDRESS={{ ORACLE_SHUTDOWN_CONTRACT_ADDRESS }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_SHUTDOWN_CONTRACT_METHOD | default('') != '' %}
|
|
||||||
ORACLE_SHUTDOWN_CONTRACT_METHOD={{ ORACLE_SHUTDOWN_CONTRACT_METHOD }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if ORACLE_HOME_START_BLOCK | default('') != '' %}
|
|
||||||
ORACLE_HOME_START_BLOCK={{ ORACLE_HOME_START_BLOCK }}
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_FOREIGN_START_BLOCK | default('') != '' %}
|
|
||||||
ORACLE_FOREIGN_START_BLOCK={{ ORACLE_FOREIGN_START_BLOCK }}
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
$FileCreateMode 0644
|
|
||||||
template(name="DockerLogFileName_Oracle" type="list") {
|
|
||||||
constant(value="/var/log/docker/")
|
|
||||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="bridge_(.*)\\/[a-zA-Z0-9]+\\[")
|
|
||||||
constant(value="/docker.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if $programname startswith 'oracle_bridge_' then \
|
|
||||||
?DockerLogFileName_Oracle
|
|
||||||
|
|
||||||
$FileCreateMode 0600
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
$FileCreateMode 0644
|
|
||||||
template(name="DockerLogFileName_Redis" type="list") {
|
|
||||||
constant(value="/var/log/docker/")
|
|
||||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*redis.*)\\/[a-zA-Z0-9]+\\[")
|
|
||||||
constant(value="/docker.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if $programname contains 'oracle' and $programname contains 'redis' then \
|
|
||||||
?DockerLogFileName_Redis
|
|
||||||
|
|
||||||
$FileCreateMode 0600
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
$FileCreateMode 0644
|
|
||||||
template(name="DockerLogFileName_Rabbit" type="list") {
|
|
||||||
constant(value="/var/log/docker/")
|
|
||||||
property(name="syslogtag" securepath="replace" regex.type="ERE" regex.submatch="1" regex.expression="oracle_(.*rabbit.*)\\/[a-zA-Z0-9]+\\[")
|
|
||||||
constant(value="/docker.log")
|
|
||||||
}
|
|
||||||
|
|
||||||
if $programname contains 'oracle' and $programname contains 'rabbit' then \
|
|
||||||
?DockerLogFileName_Rabbit
|
|
||||||
|
|
||||||
$FileCreateMode 0600
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
if $programname startswith 'oracle_bridge_' then {
|
|
||||||
action(
|
|
||||||
type="omfwd"
|
|
||||||
protocol="{{ syslog_server_port.split(":")[0] }}"
|
|
||||||
target="{{ (syslog_server_port.split(":")[1])[2:] }}"
|
|
||||||
port="{{ syslog_server_port.split(":")[2] }}"
|
|
||||||
template="RemoteForwardFormat"
|
|
||||||
queue.SpoolDirectory="/var/spool/rsyslog"
|
|
||||||
queue.FileName="remote"
|
|
||||||
queue.MaxDiskSpace="1g"
|
|
||||||
queue.SaveOnShutdown="on"
|
|
||||||
queue.Type="LinkedList"
|
|
||||||
ResendLastMSGOnReconnect="on"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
version: '3.9'
|
|
||||||
x-deploy: &x-deploy
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
cpus: '0.3'
|
|
||||||
memory: 500M
|
|
||||||
reservations:
|
|
||||||
memory: 100M
|
|
||||||
x-keystore-access: &x-keystore-access
|
|
||||||
environment:
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH: /run/secrets/oracle_keystore
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD:
|
|
||||||
secrets:
|
|
||||||
- oracle_keystore
|
|
||||||
x-logging: &x-logging
|
|
||||||
driver: 'syslog'
|
|
||||||
options: {tag: '{{ '{{.Name}}/{{.ID}}' }}' }
|
|
||||||
services:
|
|
||||||
rabbit:
|
|
||||||
image: rabbitmq:3
|
|
||||||
hostname: rabbit
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
environment: [ 'RABBITMQ_NODENAME=node@rabbit' ]
|
|
||||||
networks:
|
|
||||||
- net_rabbit_bridge_request
|
|
||||||
- net_rabbit_bridge_collected
|
|
||||||
- net_rabbit_bridge_affirmation
|
|
||||||
- net_rabbit_bridge_senderhome
|
|
||||||
- net_rabbit_bridge_senderforeign
|
|
||||||
volumes: [ '{{ bridge_data_path }}/rabbitmq:/var/lib/rabbitmq/mnesia' ]
|
|
||||||
redis:
|
|
||||||
image: redis:4
|
|
||||||
hostname: redis
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
command: [ redis-server, --appendonly, 'yes' ]
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_request
|
|
||||||
- net_db_bridge_collected
|
|
||||||
- net_db_bridge_affirmation
|
|
||||||
- net_db_bridge_senderhome
|
|
||||||
- net_db_bridge_senderforeign
|
|
||||||
- net_db_bridge_shutdown
|
|
||||||
volumes: [ '{{ bridge_data_path }}/redis:/data' ]
|
|
||||||
bridge_request:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
env_file: ./.env
|
|
||||||
<<: *x-keystore-access
|
|
||||||
entrypoint: yarn watcher:signature-request
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_request
|
|
||||||
- net_rabbit_bridge_request
|
|
||||||
bridge_collected:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
env_file: ./.env
|
|
||||||
entrypoint: yarn watcher:collected-signatures
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_collected
|
|
||||||
- net_rabbit_bridge_collected
|
|
||||||
bridge_affirmation:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
env_file: ./.env
|
|
||||||
entrypoint: yarn watcher:affirmation-request
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_affirmation
|
|
||||||
- net_rabbit_bridge_affirmation
|
|
||||||
bridge_senderhome:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
env_file: ./.env
|
|
||||||
<<: *x-keystore-access
|
|
||||||
entrypoint: yarn sender:home
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_senderhome
|
|
||||||
- net_rabbit_bridge_senderhome
|
|
||||||
bridge_senderforeign:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
env_file: ./.env
|
|
||||||
<<: *x-keystore-access
|
|
||||||
entrypoint: yarn sender:foreign
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_senderforeign
|
|
||||||
- net_rabbit_bridge_senderforeign
|
|
||||||
bridge_shutdown:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
env_file: ./.env
|
|
||||||
entrypoint: yarn manager:shutdown
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_shutdown
|
|
||||||
{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %}
|
|
||||||
bridge_transfer:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
env_file: ./.env
|
|
||||||
entrypoint: yarn watcher:transfer
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_transfer
|
|
||||||
- net_rabbit_bridge_transfer
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %}
|
|
||||||
bridge_information:
|
|
||||||
image: {{ oracle_image }}
|
|
||||||
deploy: *x-deploy
|
|
||||||
logging: *x-logging
|
|
||||||
env_file: ./.env
|
|
||||||
entrypoint: yarn watcher:information-request
|
|
||||||
networks:
|
|
||||||
- net_db_bridge_information
|
|
||||||
- net_rabbit_bridge_information
|
|
||||||
{% endif %}
|
|
||||||
networks:
|
|
||||||
net_db_bridge_request:
|
|
||||||
net_db_bridge_collected:
|
|
||||||
net_db_bridge_affirmation:
|
|
||||||
net_db_bridge_senderhome:
|
|
||||||
net_db_bridge_senderforeign:
|
|
||||||
net_db_bridge_shutdown:
|
|
||||||
{% if ORACLE_BRIDGE_MODE == "ERC_TO_NATIVE" %}
|
|
||||||
net_db_bridge_transfer:
|
|
||||||
net_rabbit_bridge_transfer:
|
|
||||||
{% endif %}
|
|
||||||
{% if ORACLE_BRIDGE_MODE == "ARBITRARY_MESSAGE" %}
|
|
||||||
net_db_bridge_information:
|
|
||||||
net_rabbit_bridge_information:
|
|
||||||
{% endif %}
|
|
||||||
net_rabbit_bridge_request:
|
|
||||||
net_rabbit_bridge_collected:
|
|
||||||
net_rabbit_bridge_affirmation:
|
|
||||||
net_rabbit_bridge_senderhome:
|
|
||||||
net_rabbit_bridge_senderforeign:
|
|
||||||
|
|
||||||
secrets:
|
|
||||||
oracle_keystore:
|
|
||||||
external: true
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
## Validator-specific options
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD={{ ORACLE_VALIDATOR_KEYSTORE_PASSWORD }}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: poabridge
|
|
||||||
# Required-Start: $remote_fs $syslog
|
|
||||||
# Required-Stop: $remote_fs $syslog
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Start daemon at boot time
|
|
||||||
# Description: Enable service provided by daemon.
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
WORKDIR="{{ '/home/' + compose_service_user | default('poadocker') + '/' + bridge_path + '/oracle' if bridge_path[:1] != "/" else bridge_path + '/oracle' }}"
|
|
||||||
|
|
||||||
#Getting path to private key file and variable name for parsing key file
|
|
||||||
source {{ keyfile_path }}
|
|
||||||
|
|
||||||
start(){
|
|
||||||
echo "Starting bridge.."
|
|
||||||
cd $WORKDIR
|
|
||||||
sudo -u "{{ compose_service_user }}" docker stack rm oracle
|
|
||||||
sudo -u "{{ compose_service_user }}" "ORACLE_VALIDATOR_KEYSTORE_PASSWORD=$ORACLE_VALIDATOR_KEYSTORE_PASSWORD" docker stack deploy oracle -c docker-compose.yml
|
|
||||||
}
|
|
||||||
|
|
||||||
stop(){
|
|
||||||
echo "Stopping bridge.."
|
|
||||||
cd $WORKDIR
|
|
||||||
sudo -u "{{ compose_service_user }}" docker stack rm oracle
|
|
||||||
sleep 2
|
|
||||||
}
|
|
||||||
|
|
||||||
status(){
|
|
||||||
echo "Bridge status:"
|
|
||||||
cd $WORKDIR
|
|
||||||
sudo -u "{{ compose_service_user }}" docker service ls
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
|
|
||||||
restart)
|
|
||||||
echo "Restarting bridge.."
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo $"Usage: $0 {start|stop|restart|status}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -4,11 +4,6 @@
|
|||||||
become: true
|
become: true
|
||||||
roles:
|
roles:
|
||||||
- { role: oracle }
|
- { role: oracle }
|
||||||
- name: Install Oracle as a Docker Swarm service
|
|
||||||
hosts: oracle_swarm
|
|
||||||
become: true
|
|
||||||
roles:
|
|
||||||
- { role: oracle_swarm }
|
|
||||||
- name: Install Monitor
|
- name: Install Monitor
|
||||||
hosts: monitor
|
hosts: monitor
|
||||||
become: true
|
become: true
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ COMMON_HOME_RPC_URL=http://parity1:8545
|
|||||||
COMMON_FOREIGN_RPC_URL=http://parity2:8545
|
COMMON_FOREIGN_RPC_URL=http://parity2:8545
|
||||||
COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
|
COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
|
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
|
||||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=
|
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||||
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
|
||||||
|
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
||||||
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
|
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
|
||||||
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
|
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
|
||||||
COMMON_HOME_GAS_PRICE_FACTOR=1
|
COMMON_HOME_GAS_PRICE_FACTOR=1
|
||||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=
|
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000
|
||||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
|
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ COMMON_HOME_RPC_URL=http://parity1:8545
|
|||||||
COMMON_FOREIGN_RPC_URL=http://parity2:8545
|
COMMON_FOREIGN_RPC_URL=http://parity2:8545
|
||||||
COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c
|
COMMON_HOME_BRIDGE_ADDRESS=0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
|
COMMON_FOREIGN_BRIDGE_ADDRESS=0x32198D570fffC7033641F8A9094FFDCaAEF42624
|
||||||
|
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
|
||||||
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
|
||||||
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||||
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
|
||||||
COMMON_HOME_GAS_PRICE_FALLBACK=1
|
COMMON_HOME_GAS_PRICE_FALLBACK=1
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
"ercToNativeBridge": {
|
"ercToNativeBridge": {
|
||||||
"home": "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c",
|
"home": "0x5118AC62AE912Dd5B51EEfF7338c4fcb0248Ba8c",
|
||||||
"foreign": "0x32198D570fffC7033641F8A9094FFDCaAEF42624",
|
"foreign": "0x32198D570fffC7033641F8A9094FFDCaAEF42624",
|
||||||
"foreignToken": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
|
"foreignToken": "0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9",
|
||||||
"monitor": "http://monitor-erc20-native:3012/bridge"
|
"monitor": "http://monitor-erc20-native:3012/bridge"
|
||||||
},
|
},
|
||||||
"amb": {
|
"amb": {
|
||||||
@@ -49,12 +49,6 @@
|
|||||||
"blockedHomeBox": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977",
|
"blockedHomeBox": "0xF9698Eb93702dfdd0e2d802088d4c21822a8A977",
|
||||||
"monitor": "http://monitor-amb:3013/bridge"
|
"monitor": "http://monitor-amb:3013/bridge"
|
||||||
},
|
},
|
||||||
"amb2": {
|
|
||||||
"home": "0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9",
|
|
||||||
"foreign": "0x897527391ad3837604973d78D3514f44c36AB9FC",
|
|
||||||
"homeBox": "0xb008E9076fCbDB2C3AF84225Bc07Eb35B2bE5ECD",
|
|
||||||
"foreignBox": "0x4a58D6d8D416a5fBCAcf3dC52eb8bE8948E25127"
|
|
||||||
},
|
|
||||||
"homeRPC": {
|
"homeRPC": {
|
||||||
"URL": "http://parity1:8545",
|
"URL": "http://parity1:8545",
|
||||||
"ID": "77"
|
"ID": "77"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ FOREIGN_GAS_PRICE=10000000000
|
|||||||
FOREIGN_REWARDABLE=false
|
FOREIGN_REWARDABLE=false
|
||||||
|
|
||||||
BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B
|
BLOCK_REWARD_ADDRESS=0xdbeE25CbE97e4A5CC6c499875774dc7067E9426B
|
||||||
ERC20_TOKEN_ADDRESS=0x6B175474E89094C44Da98b954EedeAC495271d0F
|
ERC20_TOKEN_ADDRESS=0x7cc4b1851c35959d34e635a470f6b5c43ba3c9c9
|
||||||
|
|
||||||
REQUIRED_NUMBER_OF_VALIDATORS=1
|
REQUIRED_NUMBER_OF_VALIDATORS=1
|
||||||
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
|
VALIDATORS="0xaaB52d66283F7A1D5978bcFcB55721ACB467384b 0xdCC784657C78054aa61FbcFFd2605F32374816A4 0xDcef88209a20D52165230104B245803C3269454d"
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
[{"version":3,"id":"e7e64a1b-5e61-4c17-a473-963d2bbb59e5","address":"d138a69eb2da1c3518e792737c820b23cce62e4b","crypto":{"ciphertext":"f6ddf0b2638fb9fd5777de2aa07937b5ee9bc17acc74c8e6e6580e2dfd0d3de6","cipherparams":{"iv":"bcdbc5af4582887e5cdcf264e8d5b80d"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"f9e621918990e64e278e0fb8cf0343219e1cceaea8547d50fae452ad8f42f231","n":8192,"r":8,"p":1},"mac":"34149cd0b3ddea52588825d403fb75cfb8b864b616d455f75f2de001cc2601ed"}}]
|
|
||||||
@@ -35,9 +35,3 @@ echo -e "\n\n############ Deploying one more test contract for amb ############\
|
|||||||
cd "$DEPLOY_PATH"
|
cd "$DEPLOY_PATH"
|
||||||
node src/utils/deployTestBox.js
|
node src/utils/deployTestBox.js
|
||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
|
|
||||||
echo -e "\n\n############ Deploying one more amb without oracle for confirm relay tests ############\n"
|
|
||||||
cp "$ENVS_PATH/amb.env" "$DEPLOY_PATH/.env"
|
|
||||||
cd "$DEPLOY_PATH"
|
|
||||||
node deploy.js
|
|
||||||
cd - > /dev/null
|
|
||||||
|
|||||||
@@ -15,46 +15,42 @@ docker network create --driver bridge ultimate || true
|
|||||||
docker-compose up -d parity1 parity2 e2e
|
docker-compose up -d parity1 parity2 e2e
|
||||||
|
|
||||||
startValidator () {
|
startValidator () {
|
||||||
db_env="-e ORACLE_QUEUE_URL=amqp://$3 -e ORACLE_REDIS_URL=redis://$2"
|
db_env="-e ORACLE_QUEUE_URL=amqp://$4 -e ORACLE_REDIS_URL=redis://$3"
|
||||||
|
|
||||||
docker-compose $1 run -d --name $2 redis
|
docker-compose $1 run -d --name $3 redis
|
||||||
docker-compose $1 run -d --name $3 rabbit
|
docker-compose $1 run -d --name $4 rabbit
|
||||||
|
|
||||||
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
|
if [[ -z "$MODE" || "$MODE" == erc-to-native ]]; then
|
||||||
docker-compose $1 run $oraclePK $db_env -d oracle-erc20-native yarn watcher:signature-request
|
docker-compose $1 run $2 $db_env -d oracle-erc20-native yarn watcher:signature-request
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-erc20-native yarn watcher:collected-signatures
|
docker-compose $1 run $2 $db_env -d oracle-erc20-native yarn watcher:collected-signatures
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-erc20-native yarn watcher:affirmation-request
|
docker-compose $1 run $2 $db_env -d oracle-erc20-native yarn watcher:affirmation-request
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-erc20-native yarn watcher:transfer
|
docker-compose $1 run $2 $db_env -d oracle-erc20-native yarn watcher:transfer
|
||||||
fi
|
fi
|
||||||
if [[ -z "$MODE" || "$MODE" == amb ]]; then
|
if [[ -z "$MODE" || "$MODE" == amb ]]; then
|
||||||
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn watcher:signature-request
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn watcher:signature-request
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:collected-signatures
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn watcher:collected-signatures
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:affirmation-request
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn watcher:affirmation-request
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn watcher:information-request
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn watcher:information-request
|
||||||
fi
|
fi
|
||||||
|
|
||||||
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn sender:home
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn sender:home
|
||||||
docker-compose $1 run $oraclePK $db_env -d oracle-amb yarn sender:foreign
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn sender:foreign
|
||||||
docker-compose $1 run $oracleAddr $db_env -d oracle-amb yarn manager:shutdown
|
docker-compose $1 run $2 $db_env -d oracle-amb yarn manager:shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
while [ "$1" != "" ]; do
|
while [ "$1" != "" ]; do
|
||||||
if [ "$1" == "oracle" ]; then
|
if [ "$1" == "oracle" ]; then
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
startValidator "-p validator1" "" redis rabbit
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
|
||||||
startValidator "-p validator1" redis rabbit
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "oracle-validator-2" ]; then
|
if [ "$1" == "oracle-validator-2" ]; then
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4"
|
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
startValidator "-p validator2" "$oracle2Values" redis2 rabbit2
|
||||||
startValidator "-p validator2" redis2 rabbit2
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "oracle-validator-3" ]; then
|
if [ "$1" == "oracle-validator-3" ]; then
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d"
|
oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
|
startValidator "-p validator3" "$oracle3Values" redis3 rabbit3
|
||||||
startValidator "-p validator3" redis3 rabbit3
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" == "alm" ]; then
|
if [ "$1" == "alm" ]; then
|
||||||
@@ -88,38 +84,13 @@ while [ "$1" != "" ]; do
|
|||||||
if [ "$1" == "alm-e2e" ]; then
|
if [ "$1" == "alm-e2e" ]; then
|
||||||
MODE=amb
|
MODE=amb
|
||||||
|
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b"
|
startValidator "-p validator1" "" redis rabbit
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
|
||||||
startValidator "-p validator1" redis rabbit
|
|
||||||
|
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4"
|
oracle2Values="-e ORACLE_VALIDATOR_ADDRESS=0xdCC784657C78054aa61FbcFFd2605F32374816A4 -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=5a5c3645d0f04e9eb4f27f94ed4c244a225587405b8838e7456f7781ce3a9513"
|
startValidator "-p validator2" "$oracle2Values" redis2 rabbit2
|
||||||
startValidator "-p validator2" redis2 rabbit2
|
|
||||||
|
|
||||||
oracleAddr="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d"
|
oracle3Values="-e ORACLE_VALIDATOR_ADDRESS=0xDcef88209a20D52165230104B245803C3269454d -e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=f877f62a1c19f852cff1d29f0fb1ecac18821c0080d4cc0520c60c098293dca1"
|
startValidator "-p validator3" "$oracle3Values" redis3 rabbit3
|
||||||
startValidator "-p validator3" redis3 rabbit3
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" == "generate-amb-tx" ]; then
|
|
||||||
docker-compose run e2e yarn workspace oracle-e2e run generate-amb-tx
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" == "manual-amb-relay" ]; then
|
|
||||||
oraclePK="-e ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9"
|
|
||||||
env="-e COMMON_HOME_BRIDGE_ADDRESS=0x5A42E119990c3F3A80Fea20aAF4c3Ff4DB240Cc9 -e COMMON_FOREIGN_BRIDGE_ADDRESS=0x897527391ad3837604973d78D3514f44c36AB9FC"
|
|
||||||
# these tx hash are hardcoded and need to be updated manually
|
|
||||||
# once e2e environment setup process is changed
|
|
||||||
echo '0xea625a823bc5018dc3a4efe349f623e5ebb8c987b55f44d50d6556f42af9a400' > txHashes.txt
|
|
||||||
docker-compose -p validator1 run -v $(pwd)/txHashes.txt:/tmp/txHashes.txt $oraclePK $env oracle-amb yarn confirm:affirmation-request \
|
|
||||||
/tmp/txHashes.txt \
|
|
||||||
0x031c42e44485002c9215a5b1b75e9516131485ce29884a58765bf7a0038538f9
|
|
||||||
docker-compose -p validator1 run $oraclePK $env oracle-amb yarn confirm:signature-request \
|
|
||||||
0x1506a18af91afe732167ccbc178b55fc2547da4a814d13c015b6f496cf171754 | tee .tmp.log
|
|
||||||
tx_hash=$(cat .tmp.log | grep generatedTransactionHash | jq -r .generatedTransactionHash)
|
|
||||||
rm .tmp.log
|
|
||||||
rm txHashes.txt
|
|
||||||
docker-compose -p validator1 run $oraclePK $env oracle-amb yarn confirm:collected-signatures $tx_hash
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
shift # Shift all the parameters down by one
|
shift # Shift all the parameters down by one
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const logger = require('./logger')('detectMediators.js')
|
const logger = require('./logger')('detectMediators.js')
|
||||||
|
const { isHomeContract, isForeignContract } = require('./utils/web3Cache')
|
||||||
const eventsInfo = require('./utils/events')
|
const eventsInfo = require('./utils/events')
|
||||||
const { getHomeTxSender, getForeignTxSender, isHomeContract, isForeignContract } = require('./utils/web3Cache')
|
const { getHomeTxSender, getForeignTxSender } = require('./utils/web3Cache')
|
||||||
const { addExecutionStatus, addRetrievalStatus } = require('./utils/message')
|
const { addExecutionStatus } = require('./utils/message')
|
||||||
const { normalizeAMBMessageEvent, normalizeAMBInfoRequest } = require('../commons')
|
const { normalizeAMBMessageEvent } = require('../commons')
|
||||||
|
|
||||||
function countInteractions(requests) {
|
function countInteractions(requests) {
|
||||||
const stats = {}
|
const stats = {}
|
||||||
@@ -29,41 +30,6 @@ function countInteractions(requests) {
|
|||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
function countInfoRequests(requests) {
|
|
||||||
const stats = {}
|
|
||||||
requests.forEach(msg => {
|
|
||||||
if (!stats[msg.sender]) {
|
|
||||||
stats[msg.sender] = {}
|
|
||||||
}
|
|
||||||
if (!stats[msg.sender][msg.requestSelector]) {
|
|
||||||
stats[msg.sender][msg.requestSelector] = {
|
|
||||||
callSucceeded: {
|
|
||||||
callbackSucceeded: 0,
|
|
||||||
callbackFailed: 0
|
|
||||||
},
|
|
||||||
callFailed: {
|
|
||||||
callbackSucceeded: 0,
|
|
||||||
callbackFailed: 0
|
|
||||||
},
|
|
||||||
pending: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const stat = stats[msg.sender][msg.requestSelector]
|
|
||||||
if (msg.callStatus === true && msg.callbackStatus === true) {
|
|
||||||
stat.callSucceeded.callbackSucceeded += 1
|
|
||||||
} else if (msg.callStatus === true && msg.callbackStatus === false) {
|
|
||||||
stat.callSucceeded.callbackFailed += 1
|
|
||||||
} else if (msg.callStatus === false && msg.callbackStatus === true) {
|
|
||||||
stat.callFailed.callbackSucceeded += 1
|
|
||||||
} else if (msg.callStatus === false && msg.callbackStatus === false) {
|
|
||||||
stat.callFailed.callbackFailed += 1
|
|
||||||
} else {
|
|
||||||
stat.pending += 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalize = event => ({
|
const normalize = event => ({
|
||||||
...normalizeAMBMessageEvent(event),
|
...normalizeAMBMessageEvent(event),
|
||||||
txHash: event.transactionHash,
|
txHash: event.transactionHash,
|
||||||
@@ -122,13 +88,10 @@ async function main(mode) {
|
|||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations
|
||||||
informationRequests,
|
|
||||||
informationResponses
|
|
||||||
} = await eventsInfo(mode)
|
} = await eventsInfo(mode)
|
||||||
const homeToForeign = homeToForeignRequests.map(normalize).map(addExecutionStatus(homeToForeignConfirmations))
|
const homeToForeign = homeToForeignRequests.map(normalize).map(addExecutionStatus(homeToForeignConfirmations))
|
||||||
const foreignToHome = foreignToHomeRequests.map(normalize).map(addExecutionStatus(foreignToHomeConfirmations))
|
const foreignToHome = foreignToHomeRequests.map(normalize).map(addExecutionStatus(foreignToHomeConfirmations))
|
||||||
const infoRequests = informationRequests.map(normalizeAMBInfoRequest).map(addRetrievalStatus(informationResponses))
|
|
||||||
|
|
||||||
for (const event of homeToForeign) {
|
for (const event of homeToForeign) {
|
||||||
// AMB contract emits a single UserRequestForSignature event for every home->foreign request.
|
// AMB contract emits a single UserRequestForSignature event for every home->foreign request.
|
||||||
@@ -183,7 +146,6 @@ async function main(mode) {
|
|||||||
floatingMediators,
|
floatingMediators,
|
||||||
remotelyControlledMediators,
|
remotelyControlledMediators,
|
||||||
unknown,
|
unknown,
|
||||||
informationReceivers: countInfoRequests(infoRequests),
|
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,19 +46,29 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
const erc20Address = await foreignBridge.methods.erc20token().call()
|
const erc20Address = await foreignBridge.methods.erc20token().call()
|
||||||
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
const erc20Contract = new web3Foreign.eth.Contract(ERC20_ABI, erc20Address)
|
||||||
|
let investedAmountInDai = 0
|
||||||
|
let bridgeDsrBalance = 0
|
||||||
|
let displayChaiToken = false
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug('calling foreignBridge.methods.isChaiTokenEnabled')
|
||||||
|
if (await foreignBridge.methods.isChaiTokenEnabled().call()) {
|
||||||
|
displayChaiToken = true
|
||||||
|
logger.debug('calling foreignBridge.methods.investedAmountInDai')
|
||||||
|
investedAmountInDai = await foreignBridge.methods.investedAmountInDai().call()
|
||||||
|
logger.debug('calling foreignBridge.methods.dsrBalance')
|
||||||
|
bridgeDsrBalance = await foreignBridge.methods.dsrBalance().call()
|
||||||
|
} else {
|
||||||
|
logger.debug('Chai token is currently disabled')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('Methods for chai token are not present')
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug('calling erc20Contract.methods.balanceOf')
|
logger.debug('calling erc20Contract.methods.balanceOf')
|
||||||
const foreignErc20Balance = await erc20Contract.methods
|
const foreignErc20Balance = await erc20Contract.methods
|
||||||
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
.balanceOf(COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
.call({}, foreignDelayedBlockNumber)
|
.call({}, foreignDelayedBlockNumber)
|
||||||
let foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
|
||||||
try {
|
|
||||||
logger.debug('calling foreignBridge.methods.investedAmount')
|
|
||||||
const invested = await foreignBridge.methods.investedAmount(erc20Address).call({}, foreignDelayedBlockNumber)
|
|
||||||
foreignErc20BalanceBN = foreignErc20BalanceBN.plus(invested)
|
|
||||||
} catch (_) {
|
|
||||||
logger.debug('compounding related methods are not present in the foreign bridge')
|
|
||||||
}
|
|
||||||
|
|
||||||
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
const homeBridge = new web3Home.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
logger.debug('calling homeBridge.methods.blockRewardContract')
|
logger.debug('calling homeBridge.methods.blockRewardContract')
|
||||||
@@ -74,16 +84,30 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
const mintedCoinsBN = new BN(mintedCoins)
|
const mintedCoinsBN = new BN(mintedCoins)
|
||||||
const burntCoinsBN = new BN(burntCoins)
|
const burntCoinsBN = new BN(burntCoins)
|
||||||
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
const totalSupplyBN = mintedCoinsBN.minus(burntCoinsBN)
|
||||||
|
const foreignErc20BalanceBN = new BN(foreignErc20Balance).plus(lateForeignConfirmationsTotalValue)
|
||||||
|
const investedAmountInDaiBN = new BN(investedAmountInDai)
|
||||||
|
const bridgeDsrBalanceBN = new BN(bridgeDsrBalance)
|
||||||
|
|
||||||
|
const diff = foreignErc20BalanceBN
|
||||||
|
.plus(investedAmountInDaiBN)
|
||||||
|
.minus(totalSupplyBN)
|
||||||
|
.toFixed()
|
||||||
|
|
||||||
|
const foreign = {
|
||||||
|
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayChaiToken) {
|
||||||
|
foreign.investedErc20Balance = Web3Utils.fromWei(investedAmountInDai)
|
||||||
|
foreign.accumulatedInterest = Web3Utils.fromWei(bridgeDsrBalanceBN.minus(investedAmountInDaiBN).toString(10))
|
||||||
|
}
|
||||||
|
|
||||||
const diff = foreignErc20BalanceBN.minus(totalSupplyBN).toFixed()
|
|
||||||
logger.debug('Done')
|
logger.debug('Done')
|
||||||
return {
|
return {
|
||||||
home: {
|
home: {
|
||||||
totalSupply: Web3Utils.fromWei(totalSupplyBN.toFixed())
|
totalSupply: Web3Utils.fromWei(totalSupplyBN.toFixed())
|
||||||
},
|
},
|
||||||
foreign: {
|
foreign,
|
||||||
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
|
||||||
},
|
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
...blockRanges,
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests
|
||||||
informationRequests,
|
|
||||||
informationResponses
|
|
||||||
} = eventsInfo
|
} = eventsInfo
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
@@ -36,9 +34,7 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
fromForeignToHomeDiff: foreignToHomeConfirmations.length - foreignToHomeRequests.length,
|
||||||
home: {
|
home: {
|
||||||
toForeign: homeToForeignRequests.length,
|
toForeign: homeToForeignRequests.length,
|
||||||
fromForeign: foreignToHomeConfirmations.length,
|
fromForeign: foreignToHomeConfirmations.length
|
||||||
informationRequests: informationRequests.length,
|
|
||||||
informationResponses: informationResponses.length
|
|
||||||
},
|
},
|
||||||
foreign: {
|
foreign: {
|
||||||
fromHome: homeToForeignConfirmations.length,
|
fromHome: homeToForeignConfirmations.length,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const {
|
|||||||
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI
|
||||||
} = require('../../commons')
|
} = require('../../commons')
|
||||||
const { normalizeEventInformation } = require('./message')
|
const { normalizeEventInformation } = require('./message')
|
||||||
|
const { filterTransferBeforeES } = require('./tokenUtils')
|
||||||
const { writeFile, readCacheFile } = require('./file')
|
const { writeFile, readCacheFile } = require('./file')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./web3')
|
||||||
const { getPastEvents } = require('./web3Cache')
|
const { getPastEvents } = require('./web3Cache')
|
||||||
@@ -100,6 +101,21 @@ async function main(mode) {
|
|||||||
chain: 'home'
|
chain: 'home'
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
homeToForeignRequests = [...homeToForeignRequests, ...homeToForeignRequestsNew]
|
homeToForeignRequests = [...homeToForeignRequests, ...homeToForeignRequestsNew]
|
||||||
|
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
|
const used = {}
|
||||||
|
const total = homeToForeignRequests.length
|
||||||
|
const onlyFirstUniqueFilter = e => {
|
||||||
|
const msgId = e.returnValues.messageId || e.transactionHash
|
||||||
|
if (used[msgId]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
used[msgId] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
homeToForeignRequests = homeToForeignRequests.filter(onlyFirstUniqueFilter)
|
||||||
|
const dropped = total - homeToForeignRequests.length
|
||||||
|
logger.debug(`Dropped ${dropped}/${total} UserRequestForSignature events with same message id`)
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug("calling foreignBridge.getPastEvents('RelayedMessage')")
|
logger.debug("calling foreignBridge.getPastEvents('RelayedMessage')")
|
||||||
const homeToForeignConfirmations = (await getPastEvents(foreignBridge, {
|
const homeToForeignConfirmations = (await getPastEvents(foreignBridge, {
|
||||||
@@ -128,27 +144,6 @@ async function main(mode) {
|
|||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew]
|
foreignToHomeRequests = [...foreignToHomeRequests, ...foreignToHomeRequestsNew]
|
||||||
|
|
||||||
let informationRequests
|
|
||||||
let informationResponses
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
|
||||||
logger.debug("calling homeBridge.getPastEvents('UserRequestForInformation')")
|
|
||||||
informationRequests = (await getPastEvents(homeBridge, {
|
|
||||||
event: 'UserRequestForInformation',
|
|
||||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
|
||||||
toBlock: homeDelayedBlockNumber,
|
|
||||||
chain: 'home'
|
|
||||||
})).map(normalizeEvent)
|
|
||||||
|
|
||||||
logger.debug("calling foreignBridge.getPastEvents('InformationRetrieved')")
|
|
||||||
informationResponses = (await getPastEvents(homeBridge, {
|
|
||||||
event: 'InformationRetrieved',
|
|
||||||
fromBlock: MONITOR_HOME_START_BLOCK,
|
|
||||||
toBlock: homeBlockNumber,
|
|
||||||
safeToBlock: homeDelayedBlockNumber,
|
|
||||||
chain: 'home'
|
|
||||||
})).map(normalizeEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isExternalErc20) {
|
if (isExternalErc20) {
|
||||||
logger.debug("calling erc20Contract.getPastEvents('Transfer')")
|
logger.debug("calling erc20Contract.getPastEvents('Transfer')")
|
||||||
let transferEvents = (await getPastEvents(erc20Contract, {
|
let transferEvents = (await getPastEvents(erc20Contract, {
|
||||||
@@ -159,32 +154,80 @@ async function main(mode) {
|
|||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
},
|
||||||
chain: 'foreign'
|
chain: 'foreign'
|
||||||
}))
|
})).map(normalizeEvent)
|
||||||
.map(normalizeEvent)
|
|
||||||
.filter(e => e.recipient !== ZERO_ADDRESS) // filter mint operation during SCD-to-MCD swaps
|
|
||||||
.filter(e => e.recipient.toLowerCase() !== '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643') // filter cDai withdraws during compounding
|
|
||||||
|
|
||||||
// Get transfer events for each previously used Sai token
|
let directTransfers = transferEvents
|
||||||
const saiTokenAddress = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359'
|
const tokensSwappedAbiExists = FOREIGN_ABI.filter(e => e.type === 'event' && e.name === 'TokensSwapped')[0]
|
||||||
const halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, saiTokenAddress)
|
if (tokensSwappedAbiExists) {
|
||||||
logger.debug('Half duplex token:', saiTokenAddress)
|
logger.debug('collecting half duplex tokens participated in the bridge balance')
|
||||||
|
logger.debug("calling foreignBridge.getPastEvents('TokensSwapped')")
|
||||||
|
const tokensSwappedEvents = await getPastEvents(foreignBridge, {
|
||||||
|
event: 'TokensSwapped',
|
||||||
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
|
toBlock: foreignBlockNumber,
|
||||||
|
chain: 'foreign',
|
||||||
|
safeToBlock: foreignDelayedBlockNumber
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get token swap events emitted by foreign bridge
|
||||||
|
const bridgeTokensSwappedEvents = tokensSwappedEvents.filter(e => e.address === COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
|
|
||||||
|
// Get transfer events for each previous erc20
|
||||||
|
const uniqueTokenAddressesSet = new Set(bridgeTokensSwappedEvents.map(e => e.returnValues.from))
|
||||||
|
|
||||||
|
// Exclude chai token from previous erc20
|
||||||
|
try {
|
||||||
|
logger.debug('calling foreignBridge.chaiToken() to remove it from half duplex tokens list')
|
||||||
|
const chaiToken = await foreignBridge.methods.chaiToken().call()
|
||||||
|
uniqueTokenAddressesSet.delete(chaiToken)
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('call to foreignBridge.chaiToken() failed')
|
||||||
|
}
|
||||||
|
// Exclude dai token from previous erc20
|
||||||
|
try {
|
||||||
|
logger.debug('calling foreignBridge.erc20token() to remove it from half duplex tokens list')
|
||||||
|
const daiToken = await foreignBridge.methods.erc20token().call()
|
||||||
|
uniqueTokenAddressesSet.delete(daiToken)
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('call to foreignBridge.erc20token() failed')
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueTokenAddresses = [...uniqueTokenAddressesSet]
|
||||||
|
await Promise.all(
|
||||||
|
uniqueTokenAddresses.map(async tokenAddress => {
|
||||||
|
const halfDuplexTokenContract = new web3Foreign.eth.Contract(ERC20_ABI, tokenAddress)
|
||||||
|
|
||||||
|
logger.debug('Half duplex token:', tokenAddress)
|
||||||
logger.debug("calling halfDuplexTokenContract.getPastEvents('Transfer')")
|
logger.debug("calling halfDuplexTokenContract.getPastEvents('Transfer')")
|
||||||
// https://etherscan.io/tx/0xd0c3c92c94e05bc71256055ce8c4c993e047f04e04f3283a04e4cb077b71f6c6
|
|
||||||
const blockNumberHalfDuplexDisabled = 9884448
|
|
||||||
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
const halfDuplexTransferEvents = (await getPastEvents(halfDuplexTokenContract, {
|
||||||
event: 'Transfer',
|
event: 'Transfer',
|
||||||
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
fromBlock: MONITOR_FOREIGN_START_BLOCK,
|
||||||
toBlock: Math.min(blockNumberHalfDuplexDisabled, foreignDelayedBlockNumber),
|
toBlock: foreignDelayedBlockNumber,
|
||||||
options: {
|
options: {
|
||||||
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
filter: { to: COMMON_FOREIGN_BRIDGE_ADDRESS }
|
||||||
},
|
},
|
||||||
chain: 'foreign'
|
chain: 'foreign'
|
||||||
})).map(normalizeEvent)
|
})).map(normalizeEvent)
|
||||||
|
|
||||||
transferEvents = [...halfDuplexTransferEvents, ...transferEvents]
|
// Remove events after the ES
|
||||||
|
logger.debug('filtering half duplex transfers happened before ES')
|
||||||
|
const validHalfDuplexTransfers = await filterTransferBeforeES(halfDuplexTransferEvents)
|
||||||
|
|
||||||
|
transferEvents = [...validHalfDuplexTransfers, ...transferEvents]
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// filter transfer that is part of a token swap
|
||||||
|
directTransfers = transferEvents.filter(
|
||||||
|
e =>
|
||||||
|
bridgeTokensSwappedEvents.findIndex(
|
||||||
|
t => t.transactionHash === e.referenceTx && e.recipient === ZERO_ADDRESS
|
||||||
|
) === -1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Get transfer events that didn't have a UserRequestForAffirmation event in the same transaction
|
// Get transfer events that didn't have a UserRequestForAffirmation event in the same transaction
|
||||||
const directTransfers = transferEvents.filter(
|
directTransfers = directTransfers.filter(
|
||||||
e => foreignToHomeRequests.findIndex(t => t.referenceTx === e.referenceTx) === -1
|
e => foreignToHomeRequests.findIndex(t => t.referenceTx === e.referenceTx) === -1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -197,8 +240,6 @@ async function main(mode) {
|
|||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
informationRequests,
|
|
||||||
informationResponses,
|
|
||||||
isExternalErc20,
|
isExternalErc20,
|
||||||
bridgeMode,
|
bridgeMode,
|
||||||
homeBlockNumber,
|
homeBlockNumber,
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ function readFile(filePath, parseJson = true) {
|
|||||||
const json = JSON.parse(content)
|
const json = JSON.parse(content)
|
||||||
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
||||||
return Object.assign({}, json, { timeDiff })
|
return Object.assign({}, json, { timeDiff })
|
||||||
} catch (_) {
|
} catch (e) {
|
||||||
console.error(`File ${filePath} does not exist`)
|
console.error('readFlle', e)
|
||||||
return {
|
return {
|
||||||
error: 'the bridge statistics are not available'
|
error: 'the bridge statistics are not available'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,21 +28,6 @@ function addExecutionStatus(processedList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRetrievalStatus(retrievedInfoList) {
|
|
||||||
const statuses = {}
|
|
||||||
retrievedInfoList.forEach(e => {
|
|
||||||
statuses[e.returnValues.messageId] = {
|
|
||||||
callStatus: e.returnValues.status,
|
|
||||||
callbackStatus: e.returnValues.callbackStatus
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return deliveredMsg => {
|
|
||||||
deliveredMsg.callStatus = statuses[deliveredMsg.messageId].callStatus
|
|
||||||
deliveredMsg.callbackStatus = statuses[deliveredMsg.messageId].callbackStatus
|
|
||||||
return deliveredMsg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes the different event objects to facilitate data processing
|
* Normalizes the different event objects to facilitate data processing
|
||||||
* @param {Object} event
|
* @param {Object} event
|
||||||
@@ -104,7 +89,6 @@ module.exports = {
|
|||||||
deliveredMsgNotProcessed,
|
deliveredMsgNotProcessed,
|
||||||
processedMsgNotDelivered,
|
processedMsgNotDelivered,
|
||||||
addExecutionStatus,
|
addExecutionStatus,
|
||||||
addRetrievalStatus,
|
|
||||||
normalizeEventInformation,
|
normalizeEventInformation,
|
||||||
eventWithoutReference,
|
eventWithoutReference,
|
||||||
unclaimedHomeToForeignRequests,
|
unclaimedHomeToForeignRequests,
|
||||||
|
|||||||
27
monitor/utils/tokenUtils.js
Normal file
27
monitor/utils/tokenUtils.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// https://etherscan.io/tx/0xd0c3c92c94e05bc71256055ce8c4c993e047f04e04f3283a04e4cb077b71f6c6
|
||||||
|
const blockNumberHalfDuplexDisabled = 9884448
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the event was before the bridge stopped supporting half duplex transfers.
|
||||||
|
*/
|
||||||
|
async function transferBeforeES(event) {
|
||||||
|
return event.blockNumber < blockNumberHalfDuplexDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
async function filterTransferBeforeES(array) {
|
||||||
|
const newArray = []
|
||||||
|
// Iterate events from newer to older
|
||||||
|
for (let i = array.length - 1; i >= 0; i--) {
|
||||||
|
const beforeES = await transferBeforeES(array[i])
|
||||||
|
if (beforeES) {
|
||||||
|
// add element to first position so the new array will have the same order
|
||||||
|
newArray.unshift(array[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArray
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
filterTransferBeforeES,
|
||||||
|
blockNumberHalfDuplexDisabled
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const Web3Utils = require('web3').utils
|
const Web3Utils = require('web3').utils
|
||||||
|
const fetch = require('node-fetch')
|
||||||
const logger = require('./logger')('validators')
|
const logger = require('./logger')('validators')
|
||||||
const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, gasPriceFromSupplier } = require('../commons')
|
const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, gasPriceFromSupplier } = require('../commons')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
||||||
@@ -80,7 +81,7 @@ async function main(bridgeMode) {
|
|||||||
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
|
||||||
logger.debug('calling home getGasPrices')
|
logger.debug('calling home getGasPrices')
|
||||||
homeGasPrice =
|
homeGasPrice =
|
||||||
(await gasPriceFromSupplier(COMMON_HOME_GAS_PRICE_SUPPLIER_URL, homeGasPriceSupplierOpts)) ||
|
(await gasPriceFromSupplier(() => fetch(COMMON_HOME_GAS_PRICE_SUPPLIER_URL), homeGasPriceSupplierOpts)) ||
|
||||||
Web3Utils.toBN(COMMON_HOME_GAS_PRICE_FALLBACK)
|
Web3Utils.toBN(COMMON_HOME_GAS_PRICE_FALLBACK)
|
||||||
homeGasPriceGwei = Web3Utils.fromWei(homeGasPrice.toString(), 'gwei')
|
homeGasPriceGwei = Web3Utils.fromWei(homeGasPrice.toString(), 'gwei')
|
||||||
homeTxCost = homeGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_HOME_TX_LIMIT))
|
homeTxCost = homeGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_HOME_TX_LIMIT))
|
||||||
@@ -92,9 +93,13 @@ async function main(bridgeMode) {
|
|||||||
|
|
||||||
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
|
||||||
logger.debug('calling foreign getGasPrices')
|
logger.debug('calling foreign getGasPrices')
|
||||||
|
const fetchFn =
|
||||||
|
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL === 'gas-price-oracle'
|
||||||
|
? null
|
||||||
|
: () => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL)
|
||||||
|
|
||||||
foreignGasPrice =
|
foreignGasPrice =
|
||||||
(await gasPriceFromSupplier(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL, foreignGasPriceSupplierOpts)) ||
|
(await gasPriceFromSupplier(fetchFn, foreignGasPriceSupplierOpts)) ||
|
||||||
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
|
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
|
||||||
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
|
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
|
||||||
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))
|
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "mocha",
|
"start": "mocha",
|
||||||
"generate-amb-tx": "node ./scripts/generate-amb-tx.js",
|
|
||||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||||
"amb": "mocha test/amb.js",
|
"amb": "mocha test/amb.js",
|
||||||
"erc-to-native": "mocha test/ercToNative.js",
|
"erc-to-native": "mocha test/ercToNative.js",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ case "$mode" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
MODE="$mode" ../e2e-commons/up.sh deploy generate-amb-tx manual-amb-relay blocks oracle oracle-validator-2 oracle-validator-3
|
MODE="$mode" ../e2e-commons/up.sh deploy blocks oracle oracle-validator-2 oracle-validator-3
|
||||||
|
|
||||||
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start $script
|
docker-compose -f ../e2e-commons/docker-compose.yml run e2e yarn workspace oracle-e2e run start $script
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
const Web3 = require('web3')
|
|
||||||
const { user, homeRPC, foreignRPC, amb2: amb } = require('../../e2e-commons/constants.json')
|
|
||||||
const { BOX_ABI } = require('../../commons')
|
|
||||||
|
|
||||||
const homeWeb3 = new Web3(new Web3.providers.HttpProvider(homeRPC.URL))
|
|
||||||
const foreignWeb3 = new Web3(new Web3.providers.HttpProvider(foreignRPC.URL))
|
|
||||||
|
|
||||||
homeWeb3.eth.accounts.wallet.add(user.privateKey)
|
|
||||||
foreignWeb3.eth.accounts.wallet.add(user.privateKey)
|
|
||||||
|
|
||||||
const opts = {
|
|
||||||
from: user.address,
|
|
||||||
gas: 400000,
|
|
||||||
gasPrice: '1'
|
|
||||||
}
|
|
||||||
const homeBox = new homeWeb3.eth.Contract(BOX_ABI, amb.homeBox, opts)
|
|
||||||
const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox, opts)
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const res1 = await homeBox.methods.setValueOnOtherNetwork(123, amb.home, amb.foreignBox).send()
|
|
||||||
const res2 = await foreignBox.methods.setValueOnOtherNetwork(456, amb.foreign, amb.homeBox).send()
|
|
||||||
const res3 = await foreignBox.methods.setValueOnOtherNetwork(789, amb.foreign, amb.homeBox).send()
|
|
||||||
|
|
||||||
console.log(res1.transactionHash)
|
|
||||||
console.log(res2.transactionHash)
|
|
||||||
console.log(res3.transactionHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const { ASYNC_CALL_ERRORS } = require('../../oracle/src/utils/constants')
|
|
||||||
const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json')
|
const { user, homeRPC, foreignRPC, amb, validator } = require('../../e2e-commons/constants.json')
|
||||||
const { uniformRetry } = require('../../e2e-commons/utils')
|
const { uniformRetry } = require('../../e2e-commons/utils')
|
||||||
const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI, ambInformationSignatures } = require('../../commons')
|
const { BOX_ABI, HOME_AMB_ABI, FOREIGN_AMB_ABI } = require('../../commons')
|
||||||
const { delay, setRequiredSignatures } = require('./utils')
|
const { delay, setRequiredSignatures } = require('./utils')
|
||||||
|
|
||||||
const { toBN } = Web3.utils
|
const { toBN } = Web3.utils
|
||||||
@@ -27,49 +26,27 @@ const foreignBox = new foreignWeb3.eth.Contract(BOX_ABI, amb.foreignBox, opts)
|
|||||||
const homeBridge = new homeWeb3.eth.Contract(HOME_AMB_ABI, amb.home, opts)
|
const homeBridge = new homeWeb3.eth.Contract(HOME_AMB_ABI, amb.home, opts)
|
||||||
const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, amb.foreign, opts)
|
const foreignBridge = new foreignWeb3.eth.Contract(FOREIGN_AMB_ABI, amb.foreign, opts)
|
||||||
|
|
||||||
function validateBlock(web3, serialized, block) {
|
|
||||||
assert.strictEqual(serialized.length, 2 + 64 * 12)
|
|
||||||
const values = web3.eth.abi.decodeParameter(
|
|
||||||
'(uint256,bytes32,address,uint256,uint256,bytes32,bytes32,bytes32,bytes32,uint256,uint256,uint256)',
|
|
||||||
serialized
|
|
||||||
)
|
|
||||||
assert.strictEqual(values[0], block.number.toString(), 'wrong block number returned')
|
|
||||||
assert.strictEqual(values[1], block.hash, 'wrong block hash returned')
|
|
||||||
assert.strictEqual(values[2], block.miner, 'wrong block miner returned')
|
|
||||||
assert.strictEqual(values[3], block.gasUsed.toString(), 'wrong block gasUsed returned')
|
|
||||||
assert.strictEqual(values[4], block.gasLimit.toString(), 'wrong block gasLimit returned')
|
|
||||||
assert.strictEqual(values[5], block.parentHash, 'wrong block parentHash returned')
|
|
||||||
assert.strictEqual(values[6], block.receiptsRoot, 'wrong block receiptsRoot returned')
|
|
||||||
assert.strictEqual(values[7], block.stateRoot, 'wrong block stateRoot returned')
|
|
||||||
assert.strictEqual(values[8], block.transactionsRoot, 'wrong block transactionsRoot returned')
|
|
||||||
assert.strictEqual(values[9], block.timestamp.toString(), 'wrong block timestamp returned')
|
|
||||||
assert.strictEqual(values[10], block.difficulty, 'wrong block difficulty returned')
|
|
||||||
assert.strictEqual(values[11], block.totalDifficulty, 'wrong block totalDifficulty returned')
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateTransaction(web3, serialized, tx) {
|
|
||||||
assert.strictEqual(serialized.length, 64 * 13 + tx.input.length + 56)
|
|
||||||
const values = web3.eth.abi.decodeParameter(
|
|
||||||
'(bytes32,uint256,bytes32,uint256,address,address,uint256,uint256,uint256,uint256,bytes)',
|
|
||||||
serialized
|
|
||||||
)
|
|
||||||
assert.strictEqual(values[0], tx.hash, 'wrong txHash returned')
|
|
||||||
assert.strictEqual(values[1], tx.blockNumber.toString(), 'wrong tx blockNumber returned')
|
|
||||||
assert.strictEqual(values[2], tx.blockHash.toString(), 'wrong tx blockHash returned')
|
|
||||||
assert.strictEqual(values[3], tx.transactionIndex.toString(), 'wrong tx transactionIndex returned')
|
|
||||||
assert.strictEqual(values[4], tx.from, 'wrong tx from returned')
|
|
||||||
assert.strictEqual(values[5], tx.to, 'wrong tx to returned')
|
|
||||||
assert.strictEqual(values[6], tx.value, 'wrong tx value returned')
|
|
||||||
assert.strictEqual(values[7], tx.nonce.toString(), 'wrong tx nonce returned')
|
|
||||||
assert.strictEqual(values[8], tx.gas.toString(), 'wrong tx gas returned')
|
|
||||||
assert.strictEqual(values[9], tx.gasPrice, 'wrong tx gasPrice returned')
|
|
||||||
assert.strictEqual(values[10], tx.input, 'wrong tx data returned')
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('arbitrary message bridging', () => {
|
describe('arbitrary message bridging', () => {
|
||||||
let requiredSignatures = 1
|
let requiredSignatures = 1
|
||||||
before(async () => {
|
before(async () => {
|
||||||
for (const method of ambInformationSignatures) {
|
const allowedMethods = [
|
||||||
|
'eth_call(address,bytes)',
|
||||||
|
'eth_call(address,bytes,uint256)',
|
||||||
|
'eth_call(address,address,uint256,bytes)',
|
||||||
|
'eth_blockNumber()',
|
||||||
|
'eth_getBlockByNumber()',
|
||||||
|
'eth_getBlockByNumber(uint256)',
|
||||||
|
'eth_getBlockByHash(bytes32)',
|
||||||
|
'eth_getBalance(address)',
|
||||||
|
'eth_getBalance(address,uint256)',
|
||||||
|
'eth_getTransactionCount(address)',
|
||||||
|
'eth_getTransactionCount(address,uint256)',
|
||||||
|
'eth_getTransactionByHash(bytes32)',
|
||||||
|
'eth_getTransactionReceipt(bytes32)',
|
||||||
|
'eth_getStorageAt(address,bytes32)',
|
||||||
|
'eth_getStorageAt(address,bytes32,uint256)'
|
||||||
|
]
|
||||||
|
for (const method of allowedMethods) {
|
||||||
const selector = homeWeb3.utils.soliditySha3(method)
|
const selector = homeWeb3.utils.soliditySha3(method)
|
||||||
await homeBridge.methods.enableAsyncRequestSelector(selector, true).send({ from: validator.address })
|
await homeBridge.methods.enableAsyncRequestSelector(selector, true).send({ from: validator.address })
|
||||||
}
|
}
|
||||||
@@ -103,19 +80,6 @@ describe('arbitrary message bridging', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (process.env.ULTIMATE !== 'true') {
|
|
||||||
describe('Confirm Relay', () => {
|
|
||||||
it('should process lost affirmation-request via confirm relay', async () => {
|
|
||||||
const value = await homeBox.methods.value().call()
|
|
||||||
assert(value === '789', 'incorrect value')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should process lost signature-request & collected-signatures via confirm relay', async () => {
|
|
||||||
const value = await foreignBox.methods.value().call()
|
|
||||||
assert(value === '123', 'incorrect value')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
describe('Home to Foreign', () => {
|
describe('Home to Foreign', () => {
|
||||||
describe('Subsidized Mode', () => {
|
describe('Subsidized Mode', () => {
|
||||||
it('should bridge message', async () => {
|
it('should bridge message', async () => {
|
||||||
@@ -124,13 +88,12 @@ describe('arbitrary message bridging', () => {
|
|||||||
const initialValue = await foreignBox.methods.value().call()
|
const initialValue = await foreignBox.methods.value().call()
|
||||||
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
||||||
|
|
||||||
const res = await homeBox.methods
|
await homeBox.methods
|
||||||
.setValueOnOtherNetwork(newValue, amb.home, amb.foreignBox)
|
.setValueOnOtherNetwork(newValue, amb.home, amb.foreignBox)
|
||||||
.send()
|
.send()
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
})
|
})
|
||||||
console.log(res.transactionHash)
|
|
||||||
|
|
||||||
// check that value changed and balance decreased
|
// check that value changed and balance decreased
|
||||||
await uniformRetry(async retry => {
|
await uniformRetry(async retry => {
|
||||||
@@ -177,6 +140,73 @@ describe('arbitrary message bridging', () => {
|
|||||||
const value = await foreignBox.methods.value().call()
|
const value = await foreignBox.methods.value().call()
|
||||||
assert(!toBN(value).eq(toBN(newValue)), 'Message should not be relayed by oracle automatically')
|
assert(!toBN(value).eq(toBN(newValue)), 'Message should not be relayed by oracle automatically')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should reconfirm message in case of validators change', async () => {
|
||||||
|
const newValue = 15
|
||||||
|
|
||||||
|
const initialValue = await foreignBox.methods.value().call()
|
||||||
|
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
||||||
|
|
||||||
|
const signatures = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: 'latest'
|
||||||
|
})
|
||||||
|
|
||||||
|
const { events } = await homeBox.methods
|
||||||
|
.setValueOnOtherNetworkUsingManualLane(newValue, amb.home, amb.foreignBox)
|
||||||
|
.send()
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e)
|
||||||
|
})
|
||||||
|
const message = homeWeb3.eth.abi.decodeParameter('bytes', events['0'].raw.data)
|
||||||
|
|
||||||
|
await delay(10000)
|
||||||
|
|
||||||
|
await setRequiredSignatures({
|
||||||
|
bridgeContract: homeBridge,
|
||||||
|
web3: homeWeb3,
|
||||||
|
requiredSignatures: 3,
|
||||||
|
options: {
|
||||||
|
from: validator.address,
|
||||||
|
gas: '4000000'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const signatures2 = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: 'latest'
|
||||||
|
})
|
||||||
|
|
||||||
|
assert(
|
||||||
|
signatures2.length === signatures.length + requiredSignatures,
|
||||||
|
`Incorrect amount of signatures submitted, got ${signatures2.length}, expected ${signatures.length +
|
||||||
|
requiredSignatures}`
|
||||||
|
)
|
||||||
|
|
||||||
|
await homeBridge.methods.requestMessageReconfirm(message).send()
|
||||||
|
|
||||||
|
await delay(10000)
|
||||||
|
|
||||||
|
const signatures3 = await homeBridge.getPastEvents('SignedForUserRequest', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: 'latest'
|
||||||
|
})
|
||||||
|
|
||||||
|
assert(
|
||||||
|
signatures3.length === signatures.length + 3,
|
||||||
|
`Incorrect amount of signatures submitted, got ${signatures3.length}, expected ${signatures.length + 3}`
|
||||||
|
)
|
||||||
|
|
||||||
|
await setRequiredSignatures({
|
||||||
|
bridgeContract: homeBridge,
|
||||||
|
web3: homeWeb3,
|
||||||
|
requiredSignatures: 2,
|
||||||
|
options: {
|
||||||
|
from: validator.address,
|
||||||
|
gas: '4000000'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should confirm but not relay message from manual lane', async () => {
|
it('should confirm but not relay message from manual lane', async () => {
|
||||||
@@ -223,13 +253,12 @@ describe('arbitrary message bridging', () => {
|
|||||||
const initialValue = await homeBox.methods.value().call()
|
const initialValue = await homeBox.methods.value().call()
|
||||||
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
assert(!toBN(initialValue).eq(toBN(newValue)), 'initial value should be different from new value')
|
||||||
|
|
||||||
const res = await foreignBox.methods
|
await foreignBox.methods
|
||||||
.setValueOnOtherNetwork(newValue, amb.foreign, amb.homeBox)
|
.setValueOnOtherNetwork(newValue, amb.foreign, amb.homeBox)
|
||||||
.send()
|
.send()
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
})
|
})
|
||||||
console.log(res.transactionHash)
|
|
||||||
|
|
||||||
// check that value changed and balance decreased
|
// check that value changed and balance decreased
|
||||||
await uniformRetry(async retry => {
|
await uniformRetry(async retry => {
|
||||||
@@ -304,7 +333,7 @@ describe('arbitrary message bridging', () => {
|
|||||||
await makeAsyncCall(selector, data2)
|
await makeAsyncCall(selector, data2)
|
||||||
|
|
||||||
assert(!(await homeBox.methods.status().call()), 'status is true')
|
assert(!(await homeBox.methods.status().call()), 'status is true')
|
||||||
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect')
|
assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
|
||||||
|
|
||||||
const data3 = homeWeb3.eth.abi.encodeParameters(
|
const data3 = homeWeb3.eth.abi.encodeParameters(
|
||||||
['address', 'address', 'uint256', 'bytes'],
|
['address', 'address', 'uint256', 'bytes'],
|
||||||
@@ -314,7 +343,7 @@ describe('arbitrary message bridging', () => {
|
|||||||
await makeAsyncCall(selector, data3)
|
await makeAsyncCall(selector, data3)
|
||||||
|
|
||||||
assert(!(await homeBox.methods.status().call()), 'status is true')
|
assert(!(await homeBox.methods.status().call()), 'status is true')
|
||||||
assert.strictEqual(await homeBox.methods.data().call(), ASYNC_CALL_ERRORS.REVERT, 'returned data is incorrect')
|
assert.strictEqual(await homeBox.methods.data().call(), null, 'returned data is incorrect')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_call for specific block', async () => {
|
it('should make async eth_call for specific block', async () => {
|
||||||
@@ -323,7 +352,7 @@ describe('arbitrary message bridging', () => {
|
|||||||
const selector = homeWeb3.utils.soliditySha3('eth_call(address,bytes,uint256)')
|
const selector = homeWeb3.utils.soliditySha3('eth_call(address,bytes,uint256)')
|
||||||
const data1 = homeWeb3.eth.abi.encodeParameters(
|
const data1 = homeWeb3.eth.abi.encodeParameters(
|
||||||
['address', 'bytes', 'uint256'],
|
['address', 'bytes', 'uint256'],
|
||||||
[amb.foreignBox, foreignBox.methods.value().encodeABI(), 25]
|
[amb.foreignBox, foreignBox.methods.value().encodeABI(), 60]
|
||||||
)
|
)
|
||||||
const data2 = homeWeb3.eth.abi.encodeParameters(
|
const data2 = homeWeb3.eth.abi.encodeParameters(
|
||||||
['address', 'bytes', 'uint256'],
|
['address', 'bytes', 'uint256'],
|
||||||
@@ -355,11 +384,6 @@ describe('arbitrary message bridging', () => {
|
|||||||
await makeAsyncCall(selector, data3)
|
await makeAsyncCall(selector, data3)
|
||||||
|
|
||||||
assert(!(await homeBox.methods.status().call()), 'status is true')
|
assert(!(await homeBox.methods.status().call()), 'status is true')
|
||||||
assert.strictEqual(
|
|
||||||
await homeBox.methods.data().call(),
|
|
||||||
ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE,
|
|
||||||
'returned data is incorrect'
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_blockNumber', async () => {
|
it('should make async eth_blockNumber', async () => {
|
||||||
@@ -379,8 +403,15 @@ describe('arbitrary message bridging', () => {
|
|||||||
|
|
||||||
assert(await homeBox.methods.status().call(), 'status is false')
|
assert(await homeBox.methods.status().call(), 'status is false')
|
||||||
const data = await homeBox.methods.data().call()
|
const data = await homeBox.methods.data().call()
|
||||||
|
assert.strictEqual(data.length, 2 + 64 * 3)
|
||||||
|
const { 0: number, 1: hash, 2: miner } = homeWeb3.eth.abi.decodeParameters(
|
||||||
|
['uint256', 'bytes32', 'address'],
|
||||||
|
data
|
||||||
|
)
|
||||||
const block = await foreignWeb3.eth.getBlock(blockNumber)
|
const block = await foreignWeb3.eth.getBlock(blockNumber)
|
||||||
validateBlock(homeWeb3, data, block)
|
assert.strictEqual(number, blockNumber, 'wrong block number returned')
|
||||||
|
assert.strictEqual(hash, block.hash, 'wrong block hash returned')
|
||||||
|
assert.strictEqual(miner, block.miner, 'wrong block miner returned')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getBlockByNumber and return latest block', async () => {
|
it('should make async eth_getBlockByNumber and return latest block', async () => {
|
||||||
@@ -390,7 +421,7 @@ describe('arbitrary message bridging', () => {
|
|||||||
|
|
||||||
assert(await homeBox.methods.status().call(), 'status is false')
|
assert(await homeBox.methods.status().call(), 'status is false')
|
||||||
const data = await homeBox.methods.data().call()
|
const data = await homeBox.methods.data().call()
|
||||||
assert.strictEqual(data.length, 2 + 64 * 12)
|
assert.strictEqual(data.length, 2 + 64 * 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getBlockByHash', async () => {
|
it('should make async eth_getBlockByHash', async () => {
|
||||||
@@ -402,7 +433,16 @@ describe('arbitrary message bridging', () => {
|
|||||||
|
|
||||||
assert(await homeBox.methods.status().call(), 'status is false')
|
assert(await homeBox.methods.status().call(), 'status is false')
|
||||||
const data = await homeBox.methods.data().call()
|
const data = await homeBox.methods.data().call()
|
||||||
validateBlock(homeWeb3, data, block)
|
assert.strictEqual(data.length, 2 + 64 * 3)
|
||||||
|
|
||||||
|
const { 0: number, 1: hash, 2: miner } = homeWeb3.eth.abi.decodeParameters(
|
||||||
|
['uint256', 'bytes32', 'address'],
|
||||||
|
data
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.strictEqual(number, blockNumber, 'wrong block number returned')
|
||||||
|
assert.strictEqual(hash, block.hash, 'wrong block hash returned')
|
||||||
|
assert.strictEqual(miner, block.miner, 'wrong block miner returned')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getBalance', async () => {
|
it('should make async eth_getBalance', async () => {
|
||||||
@@ -490,7 +530,7 @@ describe('arbitrary message bridging', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getTransactionByHash', async () => {
|
it('should make async eth_getTransactionByHash', async () => {
|
||||||
const txHash = '0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd'
|
const txHash = '0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6'
|
||||||
const tx = await foreignWeb3.eth.getTransaction(txHash)
|
const tx = await foreignWeb3.eth.getTransaction(txHash)
|
||||||
const selector = homeWeb3.utils.soliditySha3('eth_getTransactionByHash(bytes32)')
|
const selector = homeWeb3.utils.soliditySha3('eth_getTransactionByHash(bytes32)')
|
||||||
|
|
||||||
@@ -498,11 +538,32 @@ describe('arbitrary message bridging', () => {
|
|||||||
|
|
||||||
assert(await homeBox.methods.status().call(), 'status is false')
|
assert(await homeBox.methods.status().call(), 'status is false')
|
||||||
const data = await homeBox.methods.data().call()
|
const data = await homeBox.methods.data().call()
|
||||||
validateTransaction(homeWeb3, data, tx)
|
const dataTypes = [
|
||||||
|
'bytes32',
|
||||||
|
'uint256',
|
||||||
|
'address',
|
||||||
|
'address',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'uint256',
|
||||||
|
'bytes'
|
||||||
|
]
|
||||||
|
const values = homeWeb3.eth.abi.decodeParameters(dataTypes, data)
|
||||||
|
|
||||||
|
assert.strictEqual(values[0], txHash, 'wrong txHash returned')
|
||||||
|
assert.strictEqual(values[1], tx.blockNumber.toString(), 'wrong tx blockNumber returned')
|
||||||
|
assert.strictEqual(values[2], tx.from, 'wrong tx from returned')
|
||||||
|
assert.strictEqual(values[3], tx.to, 'wrong tx to returned')
|
||||||
|
assert.strictEqual(values[4], tx.value, 'wrong tx value returned')
|
||||||
|
assert.strictEqual(values[5], tx.nonce.toString(), 'wrong tx nonce returned')
|
||||||
|
assert.strictEqual(values[6], tx.gas.toString(), 'wrong tx gas returned')
|
||||||
|
assert.strictEqual(values[7], tx.gasPrice, 'wrong tx gasPrice returned')
|
||||||
|
assert.strictEqual(values[8], tx.input, 'wrong tx data returned')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getTransactionReceipt', async () => {
|
it('should make async eth_getTransactionReceipt', async () => {
|
||||||
const txHash = '0x7262f7dbe6c30599edded2137fbbe93c271b37f5c54dd27f713f0cf510e3b4dd'
|
const txHash = '0x09dfb947dbd17e27bcc117773b6e133829f7cef9646199a93ef019c4f7c0fec6'
|
||||||
const receipt = await foreignWeb3.eth.getTransactionReceipt(txHash)
|
const receipt = await foreignWeb3.eth.getTransactionReceipt(txHash)
|
||||||
const selector = homeWeb3.utils.soliditySha3('eth_getTransactionReceipt(bytes32)')
|
const selector = homeWeb3.utils.soliditySha3('eth_getTransactionReceipt(bytes32)')
|
||||||
|
|
||||||
@@ -510,25 +571,18 @@ describe('arbitrary message bridging', () => {
|
|||||||
|
|
||||||
assert(await homeBox.methods.status().call(), 'status is false')
|
assert(await homeBox.methods.status().call(), 'status is false')
|
||||||
const data = await homeBox.methods.data().call()
|
const data = await homeBox.methods.data().call()
|
||||||
const values = homeWeb3.eth.abi.decodeParameter(
|
const dataTypes = ['bytes32', 'uint256', 'bool', '(address,bytes32[],bytes)[]']
|
||||||
'(bytes32,uint256,bytes32,uint256,address,address,uint256,bool,(address,bytes32[],bytes)[])',
|
const values = homeWeb3.eth.abi.decodeParameters(dataTypes, data)
|
||||||
data
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.strictEqual(values[0], txHash, 'wrong txHash returned')
|
assert.strictEqual(values[0], txHash, 'wrong txHash returned')
|
||||||
assert.strictEqual(values[1], receipt.blockNumber.toString(), 'wrong tx blockNumber returned')
|
assert.strictEqual(values[1], receipt.blockNumber.toString(), 'wrong tx blockNumber returned')
|
||||||
assert.strictEqual(values[2], receipt.blockHash, 'wrong tx blockHash returned')
|
assert.strictEqual(values[2], receipt.status, 'wrong tx status returned')
|
||||||
assert.strictEqual(values[3], receipt.transactionIndex.toString(), 'wrong tx transactionIndex returned')
|
assert.strictEqual(values[3].length, 1, 'wrong logs length returned')
|
||||||
assert.strictEqual(values[4].toLowerCase(), receipt.from, 'wrong tx from returned')
|
assert.strictEqual(values[3][0][0], receipt.logs[0].address, 'wrong log address returned')
|
||||||
assert.strictEqual(values[5].toLowerCase(), receipt.to, 'wrong tx to returned')
|
assert.strictEqual(values[3][0][1].length, 2, 'wrong log topics length returned')
|
||||||
assert.strictEqual(values[6], receipt.gasUsed.toString(), 'wrong gasUsed to returned')
|
assert.strictEqual(values[3][0][1][0], receipt.logs[0].topics[0], 'wrong event signature returned')
|
||||||
assert.strictEqual(values[7], receipt.status, 'wrong tx status returned')
|
assert.strictEqual(values[3][0][1][1], receipt.logs[0].topics[1], 'wrong message id returned')
|
||||||
assert.strictEqual(values[8].length, 1, 'wrong logs length returned')
|
assert.strictEqual(values[3][0][2], receipt.logs[0].data, 'wrong log data returned')
|
||||||
assert.strictEqual(values[8][0][0], receipt.logs[0].address, 'wrong log address returned')
|
|
||||||
assert.strictEqual(values[8][0][1].length, 2, 'wrong log topics length returned')
|
|
||||||
assert.strictEqual(values[8][0][1][0], receipt.logs[0].topics[0], 'wrong event signature returned')
|
|
||||||
assert.strictEqual(values[8][0][1][1], receipt.logs[0].topics[1], 'wrong message id returned')
|
|
||||||
assert.strictEqual(values[8][0][2], receipt.logs[0].data, 'wrong log data returned')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should make async eth_getStorageAt', async () => {
|
it('should make async eth_getStorageAt', async () => {
|
||||||
|
|||||||
@@ -33,10 +33,6 @@ const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_TO_NATIVE_ABI, COMMON_HOME
|
|||||||
|
|
||||||
describe('erc to native', () => {
|
describe('erc to native', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
console.log('Initializing interest')
|
|
||||||
await foreignBridge.methods
|
|
||||||
.initializeInterest(ercToNativeBridge.foreignToken, 1, 1, validator.address)
|
|
||||||
.send({ from: validator.address, gas: '4000000' })
|
|
||||||
if (process.env.ULTIMATE === 'true') {
|
if (process.env.ULTIMATE === 'true') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -104,8 +100,6 @@ describe('erc to native', () => {
|
|||||||
|
|
||||||
const transferValue = homeWeb3.utils.toWei('0.05')
|
const transferValue = homeWeb3.utils.toWei('0.05')
|
||||||
|
|
||||||
// transfer that should not be processed by the filter
|
|
||||||
await erc20Token.methods.transfer(secondUser.address, transferValue).send({ from: user.address, gas: 100000 })
|
|
||||||
// send tokens to foreign bridge
|
// send tokens to foreign bridge
|
||||||
await erc20Token.methods
|
await erc20Token.methods
|
||||||
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
.transfer(COMMON_FOREIGN_BRIDGE_ADDRESS, transferValue)
|
||||||
@@ -116,7 +110,6 @@ describe('erc to native', () => {
|
|||||||
.catch(e => {
|
.catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
})
|
})
|
||||||
await foreignBridge.methods.investDai().send({ from: validator.address, gas: '4000000' })
|
|
||||||
|
|
||||||
// check that balance increases
|
// check that balance increases
|
||||||
await uniformRetry(async retry => {
|
await uniformRetry(async retry => {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ module.exports = {
|
|||||||
...baseConfig,
|
...baseConfig,
|
||||||
main: baseConfig.foreign,
|
main: baseConfig.foreign,
|
||||||
event: 'UserRequestForAffirmation',
|
event: 'UserRequestForAffirmation',
|
||||||
sender: 'home',
|
|
||||||
queue: 'home-prioritized',
|
queue: 'home-prioritized',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -8,15 +8,12 @@ const {
|
|||||||
FOREIGN_AMB_ABI
|
FOREIGN_AMB_ABI
|
||||||
} = require('../../commons')
|
} = require('../../commons')
|
||||||
const { web3Home, web3Foreign } = require('../src/services/web3')
|
const { web3Home, web3Foreign } = require('../src/services/web3')
|
||||||
const { add0xPrefix, privateKeyToAddress, loadKeystore } = require('../src/utils/utils')
|
const { privateKeyToAddress } = require('../src/utils/utils')
|
||||||
const { EXIT_CODES } = require('../src/utils/constants')
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ORACLE_BRIDGE_MODE,
|
ORACLE_BRIDGE_MODE,
|
||||||
ORACLE_VALIDATOR_ADDRESS,
|
ORACLE_VALIDATOR_ADDRESS,
|
||||||
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PATH,
|
|
||||||
ORACLE_VALIDATOR_KEYSTORE_PASSWORD,
|
|
||||||
ORACLE_MAX_PROCESSING_TIME,
|
ORACLE_MAX_PROCESSING_TIME,
|
||||||
COMMON_HOME_BRIDGE_ADDRESS,
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||||
@@ -82,33 +79,9 @@ const foreignConfig = {
|
|||||||
const maxProcessingTime =
|
const maxProcessingTime =
|
||||||
parseInt(ORACLE_MAX_PROCESSING_TIME, 10) || 4 * Math.max(homeConfig.pollingInterval, foreignConfig.pollingInterval)
|
parseInt(ORACLE_MAX_PROCESSING_TIME, 10) || 4 * Math.max(homeConfig.pollingInterval, foreignConfig.pollingInterval)
|
||||||
|
|
||||||
let validatorPrivateKey
|
|
||||||
let validatorAddress = ORACLE_VALIDATOR_ADDRESS
|
|
||||||
if (ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY) {
|
|
||||||
validatorPrivateKey = add0xPrefix(ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY)
|
|
||||||
const derived = privateKeyToAddress(validatorPrivateKey)
|
|
||||||
if (ORACLE_VALIDATOR_ADDRESS && derived.toLowerCase() !== ORACLE_VALIDATOR_ADDRESS.toLowerCase()) {
|
|
||||||
console.error(
|
|
||||||
`Derived address from private key - ${derived} is different from ORACLE_VALIDATOR_ADDRESS=${ORACLE_VALIDATOR_ADDRESS}`
|
|
||||||
)
|
|
||||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
|
||||||
}
|
|
||||||
validatorAddress = derived
|
|
||||||
} else if (ORACLE_VALIDATOR_KEYSTORE_PATH) {
|
|
||||||
try {
|
|
||||||
const keystore = loadKeystore(ORACLE_VALIDATOR_KEYSTORE_PATH, ORACLE_VALIDATOR_KEYSTORE_PASSWORD)
|
|
||||||
validatorPrivateKey = keystore.privateKey
|
|
||||||
validatorAddress = keystore.address
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Can't load keystore file: ${e.message}`)
|
|
||||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
eventFilter: {},
|
eventFilter: {},
|
||||||
validatorPrivateKey,
|
validatorAddress: ORACLE_VALIDATOR_ADDRESS || privateKeyToAddress(ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY),
|
||||||
validatorAddress,
|
|
||||||
maxProcessingTime,
|
maxProcessingTime,
|
||||||
shutdownKey: 'oracle-shutdown',
|
shutdownKey: 'oracle-shutdown',
|
||||||
home: homeConfig,
|
home: homeConfig,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ module.exports = {
|
|||||||
...baseConfig,
|
...baseConfig,
|
||||||
main: baseConfig.home,
|
main: baseConfig.home,
|
||||||
event: 'CollectedSignatures',
|
event: 'CollectedSignatures',
|
||||||
sender: 'foreign',
|
|
||||||
queue: 'foreign-prioritized',
|
queue: 'foreign-prioritized',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ module.exports = {
|
|||||||
web3ForeignArchive: web3ForeignArchive || baseConfig.foreign.web3,
|
web3ForeignArchive: web3ForeignArchive || baseConfig.foreign.web3,
|
||||||
main: baseConfig.home,
|
main: baseConfig.home,
|
||||||
event: 'UserRequestForInformation',
|
event: 'UserRequestForInformation',
|
||||||
sender: 'home',
|
|
||||||
queue: 'home-prioritized',
|
queue: 'home-prioritized',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ module.exports = {
|
|||||||
...baseConfig,
|
...baseConfig,
|
||||||
main: baseConfig.home,
|
main: baseConfig.home,
|
||||||
event: 'UserRequestForSignature',
|
event: 'UserRequestForSignature',
|
||||||
sender: 'home',
|
|
||||||
queue: 'home-prioritized',
|
queue: 'home-prioritized',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
const baseConfig = require('./base.config')
|
const baseConfig = require('./base.config')
|
||||||
const { ERC20_ABI, ZERO_ADDRESS } = require('../../commons')
|
const { ERC20_ABI } = require('../../commons')
|
||||||
const { EXIT_CODES } = require('../src/utils/constants')
|
const { EXIT_CODES } = require('../src/utils/constants')
|
||||||
|
|
||||||
|
const initialChecksJson = process.argv[3]
|
||||||
|
|
||||||
|
if (!initialChecksJson) {
|
||||||
|
throw new Error('initial check parameter was not provided.')
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialChecks
|
||||||
|
try {
|
||||||
|
initialChecks = JSON.parse(initialChecksJson)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Error on decoding values from initial checks.')
|
||||||
|
}
|
||||||
|
|
||||||
const id = `${baseConfig.id}-transfer`
|
const id = `${baseConfig.id}-transfer`
|
||||||
|
|
||||||
if (baseConfig.id !== 'erc-native') {
|
if (baseConfig.id !== 'erc-native') {
|
||||||
@@ -9,15 +22,14 @@ if (baseConfig.id !== 'erc-native') {
|
|||||||
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
|
process.exit(EXIT_CODES.WATCHER_NOT_REQUIRED)
|
||||||
}
|
}
|
||||||
|
|
||||||
// exact address of the token contract is set in the watcher.js checkConditions() function
|
|
||||||
baseConfig.foreign.eventContract = new baseConfig.foreign.web3.eth.Contract(ERC20_ABI, ZERO_ADDRESS)
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig,
|
...baseConfig,
|
||||||
main: baseConfig.foreign,
|
main: {
|
||||||
|
...baseConfig.foreign,
|
||||||
|
eventContract: new baseConfig.foreign.web3.eth.Contract(ERC20_ABI, initialChecks.bridgeableTokenAddress)
|
||||||
|
},
|
||||||
event: 'Transfer',
|
event: 'Transfer',
|
||||||
eventFilter: { to: baseConfig.foreign.bridgeAddress },
|
eventFilter: { to: process.env.COMMON_FOREIGN_BRIDGE_ADDRESS },
|
||||||
sender: 'home',
|
|
||||||
queue: 'home-prioritized',
|
queue: 'home-prioritized',
|
||||||
name: `watcher-${id}`,
|
name: `watcher-${id}`,
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
version: '2.4'
|
|
||||||
services:
|
|
||||||
interestFetcher:
|
|
||||||
cpus: 0.1
|
|
||||||
mem_limit: 500m
|
|
||||||
image: poanetwork/tokenbridge-oracle:latest
|
|
||||||
env_file: ./.env
|
|
||||||
environment:
|
|
||||||
NODE_ENV: production
|
|
||||||
INTEREST_FETCHER_PRIVATE_KEY: ${INTEREST_FETCHER_PRIVATE_KEY}
|
|
||||||
INTEREST_FETCH_CONTRACT_ADDRESS: '0xCd152c7Bd4189Ddee97EaBb783FC5cD93CF2D230'
|
|
||||||
INTERVAL: 300000
|
|
||||||
restart: unless-stopped
|
|
||||||
entrypoint: yarn helper:interestFether
|
|
||||||
@@ -13,12 +13,7 @@
|
|||||||
"sender:home": "./scripts/start-worker.sh sender home-sender",
|
"sender:home": "./scripts/start-worker.sh sender home-sender",
|
||||||
"sender:foreign": "./scripts/start-worker.sh sender foreign-sender",
|
"sender:foreign": "./scripts/start-worker.sh sender foreign-sender",
|
||||||
"confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher",
|
"confirm:transfer": "./scripts/start-worker.sh confirmRelay transfer-watcher",
|
||||||
"confirm:affirmation-request": "./scripts/start-worker.sh confirmRelay affirmation-request-watcher",
|
|
||||||
"confirm:signature-request": "./scripts/start-worker.sh confirmRelay signature-request-watcher",
|
|
||||||
"confirm:collected-signatures": "./scripts/start-worker.sh confirmRelay collected-signatures-watcher",
|
|
||||||
"confirm:information-request": "./scripts/start-worker.sh confirmRelay information-request-watcher",
|
|
||||||
"manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager",
|
"manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager",
|
||||||
"helper:interestFether": "node ./scripts/interestFetcher.js",
|
|
||||||
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
|
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
|
||||||
"test": "NODE_ENV=test mocha",
|
"test": "NODE_ENV=test mocha",
|
||||||
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
|
"test:watch": "NODE_ENV=test mocha --watch --reporter=min",
|
||||||
|
|||||||
26
oracle/scripts/initialChecks.js
Normal file
26
oracle/scripts/initialChecks.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
require('../env')
|
||||||
|
const { getTokensState } = require('../src/utils/tokenState')
|
||||||
|
const { FOREIGN_ERC_TO_NATIVE_ABI } = require('../../commons')
|
||||||
|
const { web3Foreign } = require('../src/services/web3')
|
||||||
|
|
||||||
|
const emptyLogger = {
|
||||||
|
debug: () => {},
|
||||||
|
info: () => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initialChecks() {
|
||||||
|
const { ORACLE_BRIDGE_MODE, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
||||||
|
let result = {}
|
||||||
|
|
||||||
|
if (ORACLE_BRIDGE_MODE === 'ERC_TO_NATIVE') {
|
||||||
|
const bridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_NATIVE_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
|
result = await getTokensState(bridge, emptyLogger)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(result))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = initialChecks()
|
||||||
|
|
||||||
|
module.exports = result
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
require('../env')
|
|
||||||
const { isAddress } = require('web3').utils
|
|
||||||
const { privateKeyToAddress, setIntervalAndRun } = require('../src/utils/utils')
|
|
||||||
const { EXIT_CODES } = require('../src/utils/constants')
|
|
||||||
const { web3Home } = require('../src/services/web3')
|
|
||||||
const { sendTx } = require('../src/tx/sendTx')
|
|
||||||
|
|
||||||
const privateKey = process.env.INTEREST_FETCHER_PRIVATE_KEY
|
|
||||||
const interval = process.env.INTERVAL ? parseInt(process.env.INTERVAL, 10) : 3600 * 1000
|
|
||||||
const contractAddress = process.env.INTEREST_FETCH_CONTRACT_ADDRESS
|
|
||||||
|
|
||||||
if (!privateKey) {
|
|
||||||
console.error('Environment variable INTEREST_FETCHER_PRIVATE_KEY is not set')
|
|
||||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interval < 300 * 1000) {
|
|
||||||
console.error('Interval is to small, should be at least 5 minutes')
|
|
||||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isAddress(contractAddress)) {
|
|
||||||
console.error('Invalid contract address provided', contractAddress)
|
|
||||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
const gasPrice = process.env.COMMON_HOME_GAS_PRICE_FALLBACK || '1000000000'
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
// assuming that we are using this contract - https://github.com/omni/interest-fetcher-contract
|
|
||||||
const contract = new web3Home.eth.Contract([{ name: 'fetchInterest', type: 'function', inputs: [] }], contractAddress)
|
|
||||||
const chainId = await web3Home.eth.getChainId()
|
|
||||||
const data = contract.methods.fetchInterest().encodeABI()
|
|
||||||
const senderAddress = privateKeyToAddress(privateKey)
|
|
||||||
console.log(
|
|
||||||
`Initialized, chainId=${chainId}, data=${data}, contract=${contractAddress}, interval=${interval / 1000}s`
|
|
||||||
)
|
|
||||||
|
|
||||||
await setIntervalAndRun(async () => {
|
|
||||||
let gasLimit
|
|
||||||
try {
|
|
||||||
gasLimit = await contract.methods.fetchInterest().estimateGas()
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Gas limit estimation failed, will retry later', new Date())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const nonce = await web3Home.eth.getTransactionCount(senderAddress)
|
|
||||||
|
|
||||||
const txHash = await sendTx({
|
|
||||||
privateKey,
|
|
||||||
to: contractAddress,
|
|
||||||
data,
|
|
||||||
nonce,
|
|
||||||
gasPrice,
|
|
||||||
gasLimit: Math.round(gasLimit * 1.5),
|
|
||||||
amount: '0',
|
|
||||||
chainId,
|
|
||||||
web3: web3Home
|
|
||||||
})
|
|
||||||
console.log('Sent transaction with fetch interest', txHash, new Date())
|
|
||||||
}, interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
@@ -8,10 +8,12 @@ LOGS_DIR="logs/"
|
|||||||
WORKER="${WORKERS_DIR}${1}.js"
|
WORKER="${WORKERS_DIR}${1}.js"
|
||||||
CONFIG="${2}.config.js"
|
CONFIG="${2}.config.js"
|
||||||
LOG="${LOGS_DIR}${2}.txt"
|
LOG="${LOGS_DIR}${2}.txt"
|
||||||
TX_HASH=${@:3}
|
TX_HASH="${3}"
|
||||||
|
|
||||||
|
CHECKS=$(node scripts/initialChecks.js)
|
||||||
|
|
||||||
if [ "${NODE_ENV}" = "production" ]; then
|
if [ "${NODE_ENV}" = "production" ]; then
|
||||||
exec node "${WORKER}" "${CONFIG}" $TX_HASH
|
exec node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH"
|
||||||
else
|
else
|
||||||
node "${WORKER}" "${CONFIG}" $TX_HASH | tee -a "${LOG}" | pino-pretty
|
node "${WORKER}" "${CONFIG}" "$CHECKS" "$TX_HASH" | tee -a "${LOG}" | pino-pretty
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,39 +1,22 @@
|
|||||||
require('../env')
|
require('../env')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
|
||||||
const { isAttached, connectWatcherToQueue, connection } = require('./services/amqpClient')
|
const { isAttached, connectWatcherToQueue, connection } = require('./services/amqpClient')
|
||||||
const logger = require('./services/logger')
|
const logger = require('./services/logger')
|
||||||
const GasPrice = require('./services/gasPrice')
|
const GasPrice = require('./services/gasPrice')
|
||||||
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
const { getNonce, getChainId, getEventsFromTx } = require('./tx/web3')
|
||||||
const { sendTx } = require('./tx/sendTx')
|
const { sendTx } = require('./tx/sendTx')
|
||||||
const { getTokensState } = require('./utils/tokenState')
|
|
||||||
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
const { checkHTTPS, watchdog, syncForEach, addExtraGas } = require('./utils/utils')
|
||||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
||||||
|
|
||||||
const { ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
|
const { ORACLE_VALIDATOR_ADDRESS, ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_ALLOW_HTTP_FOR_RPC } = process.env
|
||||||
|
|
||||||
if (process.argv.length < 4) {
|
if (process.argv.length < 5) {
|
||||||
logger.error('Please check the number of arguments, transaction hash is not present')
|
logger.error('Please check the number of arguments, transaction hash is not present')
|
||||||
process.exit(EXIT_CODES.GENERAL_ERROR)
|
process.exit(EXIT_CODES.GENERAL_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = require(path.join('../config/', process.argv[2]))
|
const config = require(path.join('../config/', process.argv[2]))
|
||||||
const { web3, eventContract, chain, bridgeContract } = config.main
|
const txHash = process.argv[4]
|
||||||
|
|
||||||
const isTxHash = txHash => txHash.length === 66 && web3.utils.isHexStrict(txHash)
|
|
||||||
function readTxHashes(filePath) {
|
|
||||||
return fs
|
|
||||||
.readFileSync(filePath)
|
|
||||||
.toString()
|
|
||||||
.split('\n')
|
|
||||||
.map(v => v.trim())
|
|
||||||
.filter(isTxHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
const txHashesArgs = process.argv.slice(3)
|
|
||||||
const rawTxHashes = txHashesArgs.filter(isTxHash)
|
|
||||||
const txHashesFiles = txHashesArgs.filter(path => fs.existsSync(path)).flatMap(readTxHashes)
|
|
||||||
const txHashes = [...rawTxHashes, ...txHashesFiles]
|
|
||||||
|
|
||||||
const processSignatureRequests = require('./events/processSignatureRequests')(config)
|
const processSignatureRequests = require('./events/processSignatureRequests')(config)
|
||||||
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
||||||
@@ -44,13 +27,15 @@ const processAMBCollectedSignatures = require('./events/processAMBCollectedSigna
|
|||||||
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
||||||
const processAMBInformationRequests = require('./events/processAMBInformationRequests')(config)
|
const processAMBInformationRequests = require('./events/processAMBInformationRequests')(config)
|
||||||
|
|
||||||
|
const { web3, eventContract } = config.main
|
||||||
|
|
||||||
let attached
|
let attached
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
try {
|
try {
|
||||||
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
const checkHttps = checkHTTPS(ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||||
|
|
||||||
web3.currentProvider.urls.forEach(checkHttps(chain))
|
web3.currentProvider.urls.forEach(checkHttps(config.chain))
|
||||||
|
|
||||||
attached = await isAttached()
|
attached = await isAttached()
|
||||||
if (attached) {
|
if (attached) {
|
||||||
@@ -74,12 +59,12 @@ async function runMain({ sendToQueue }) {
|
|||||||
const sendJob = attached ? sendToQueue : sendJobTx
|
const sendJob = attached ? sendToQueue : sendJobTx
|
||||||
if (!attached || connection.isConnected()) {
|
if (!attached || connection.isConnected()) {
|
||||||
if (config.maxProcessingTime) {
|
if (config.maxProcessingTime) {
|
||||||
await watchdog(() => main({ sendJob, txHashes }), config.maxProcessingTime, () => {
|
await watchdog(() => main({ sendJob, txHash }), config.maxProcessingTime, () => {
|
||||||
logger.fatal('Max processing time reached')
|
logger.fatal('Max processing time reached')
|
||||||
process.exit(EXIT_CODES.MAX_TIME_REACHED)
|
process.exit(EXIT_CODES.MAX_TIME_REACHED)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
await main({ sendJob, txHashes })
|
await main({ sendJob, txHash })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -114,17 +99,8 @@ function processEvents(events) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main({ sendJob, txHashes }) {
|
async function main({ sendJob, txHash }) {
|
||||||
if (config.id === 'erc-native-transfer') {
|
|
||||||
logger.debug('Getting token address to listen Transfer events')
|
|
||||||
const state = await getTokensState(bridgeContract, logger)
|
|
||||||
eventContract.options.address = state.bridgeableTokenAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(`Processing ${txHashes.length} input transactions`)
|
|
||||||
for (const txHash of txHashes) {
|
|
||||||
try {
|
try {
|
||||||
logger.info({ txHash }, `Processing transaction`)
|
|
||||||
const events = await getEventsFromTx({
|
const events = await getEventsFromTx({
|
||||||
web3,
|
web3,
|
||||||
contract: eventContract,
|
contract: eventContract,
|
||||||
@@ -132,11 +108,11 @@ async function main({ sendJob, txHashes }) {
|
|||||||
txHash,
|
txHash,
|
||||||
filter: config.eventFilter
|
filter: config.eventFilter
|
||||||
})
|
})
|
||||||
logger.info({ txHash }, `Found ${events.length} ${config.event} events`)
|
logger.info(`Found ${events.length} ${config.event} events`)
|
||||||
|
|
||||||
if (events.length) {
|
if (events.length) {
|
||||||
const job = await processEvents(events)
|
const job = await processEvents(events)
|
||||||
logger.info({ txHash }, 'Transactions to send:', job.length)
|
logger.info('Transactions to send:', job.length)
|
||||||
|
|
||||||
if (job.length) {
|
if (job.length) {
|
||||||
await sendJob(job)
|
await sendJob(job)
|
||||||
@@ -145,7 +121,6 @@ async function main({ sendJob, txHashes }) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await connection.close()
|
await connection.close()
|
||||||
|
|
||||||
@@ -153,13 +128,9 @@ async function main({ sendJob, txHashes }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendJobTx(jobs) {
|
async function sendJobTx(jobs) {
|
||||||
await GasPrice.start(chain, true)
|
const gasPrice = await GasPrice.start(config.chain, true)
|
||||||
const gasPrice = GasPrice.getPrice().toString(10)
|
|
||||||
|
|
||||||
const { web3 } = config.sender === 'foreign' ? config.foreign : config.home
|
|
||||||
|
|
||||||
const chainId = await getChainId(web3)
|
const chainId = await getChainId(web3)
|
||||||
let nonce = await getNonce(web3, config.validatorAddress)
|
let nonce = await getNonce(web3, ORACLE_VALIDATOR_ADDRESS)
|
||||||
|
|
||||||
await syncForEach(jobs, async job => {
|
await syncForEach(jobs, async job => {
|
||||||
let gasLimit
|
let gasLimit
|
||||||
@@ -174,10 +145,10 @@ async function sendJobTx(jobs) {
|
|||||||
const txHash = await sendTx({
|
const txHash = await sendTx({
|
||||||
data: job.data,
|
data: job.data,
|
||||||
nonce,
|
nonce,
|
||||||
gasPrice,
|
gasPrice: gasPrice.toString(10),
|
||||||
amount: '0',
|
amount: '0',
|
||||||
gasLimit,
|
gasLimit,
|
||||||
privateKey: config.validatorPrivateKey,
|
privateKey: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||||
to: job.to,
|
to: job.to,
|
||||||
chainId,
|
chainId,
|
||||||
web3
|
web3
|
||||||
@@ -196,7 +167,7 @@ async function sendJobTx(jobs) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (e.message.toLowerCase().includes('insufficient funds')) {
|
if (e.message.toLowerCase().includes('insufficient funds')) {
|
||||||
const currentBalance = await web3.eth.getBalance(config.validatorAddress)
|
const currentBalance = await web3.eth.getBalance(ORACLE_VALIDATOR_ADDRESS)
|
||||||
const minimumBalance = gasLimit.multipliedBy(gasPrice)
|
const minimumBalance = gasLimit.multipliedBy(gasPrice)
|
||||||
logger.error(
|
logger.error(
|
||||||
`Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.`
|
`Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.`
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ async function estimateGas({ web3, homeBridge, validatorContract, message, addre
|
|||||||
const gasEstimate = await homeBridge.methods.executeAffirmation(message).estimateGas({
|
const gasEstimate = await homeBridge.methods.executeAffirmation(message).estimateGas({
|
||||||
from: address
|
from: address
|
||||||
})
|
})
|
||||||
const msgGasLimit = Math.ceil((parseAMBHeader(message).gasLimit * 64) / 63)
|
const msgGasLimit = parseAMBHeader(message).gasLimit
|
||||||
// message length in bytes
|
// message length in bytes
|
||||||
const len = strip0x(message).length / 2 - MIN_AMB_HEADER_LENGTH
|
const len = strip0x(message).length / 2 - MIN_AMB_HEADER_LENGTH
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const { toBN } = require('web3').utils
|
const { toBN } = require('web3').utils
|
||||||
|
|
||||||
const { ASYNC_CALL_ERRORS, ASYNC_ETH_CALL_MAX_GAS_LIMIT } = require('../../../utils/constants')
|
const { zipToObject } = require('../../../utils/utils')
|
||||||
const { zipToObject, isRevertError } = require('../../../utils/utils')
|
|
||||||
|
|
||||||
const argTypes = {
|
const argTypes = {
|
||||||
to: 'address',
|
to: 'address',
|
||||||
@@ -18,23 +17,14 @@ function makeCall(argNames) {
|
|||||||
const { blockNumber, ...opts } = zipToObject(argNames, args)
|
const { blockNumber, ...opts } = zipToObject(argNames, args)
|
||||||
|
|
||||||
if (blockNumber && toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
if (blockNumber && toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
// different clients might use different default gas limits, so it makes sense to limit it by some large number
|
const [status, result] = await web3.eth
|
||||||
if (!opts.gas || toBN(opts.gas).gt(toBN(ASYNC_ETH_CALL_MAX_GAS_LIMIT))) {
|
|
||||||
opts.gas = ASYNC_ETH_CALL_MAX_GAS_LIMIT
|
|
||||||
}
|
|
||||||
|
|
||||||
return web3.eth
|
|
||||||
.call(opts, blockNumber || foreignBlock.number)
|
.call(opts, blockNumber || foreignBlock.number)
|
||||||
.then(result => [true, web3.eth.abi.encodeParameter('bytes', result)])
|
.then(result => [true, result], err => [false, err.data])
|
||||||
.catch(e => {
|
|
||||||
if (isRevertError(e)) {
|
return [status, web3.eth.abi.encodeParameter('bytes', result)]
|
||||||
return [false, ASYNC_CALL_ERRORS.REVERT]
|
|
||||||
}
|
|
||||||
throw e
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
const { toBN } = require('web3').utils
|
const { toBN } = require('web3').utils
|
||||||
|
|
||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
const address = web3.eth.abi.decodeParameter('address', data)
|
const address = web3.eth.abi.decodeParameter('address', data)
|
||||||
|
|
||||||
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
|
|||||||
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
||||||
|
|
||||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
const balance = await web3.eth.getBalance(address, blockNumber)
|
const balance = await web3.eth.getBalance(address, blockNumber)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
const { serializeBlock } = require('./serializers')
|
const { serializeBlock } = require('./serializers')
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
|
|||||||
const block = await web3.eth.getBlock(blockHash)
|
const block = await web3.eth.getBlock(blockHash)
|
||||||
|
|
||||||
if (block === null || block.number > foreignBlock.number) {
|
if (block === null || block.number > foreignBlock.number) {
|
||||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
return [true, serializeBlock(web3, block)]
|
return [true, serializeBlock(web3, block)]
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
const { toBN } = require('web3').utils
|
const { toBN } = require('web3').utils
|
||||||
|
|
||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
const { serializeBlock } = require('./serializers')
|
const { serializeBlock } = require('./serializers')
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
const blockNumber = web3.eth.abi.decodeParameter('uint256', data)
|
const blockNumber = web3.eth.abi.decodeParameter('uint256', data)
|
||||||
|
|
||||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
const block = await web3.eth.getBlock(blockNumber)
|
const block = await web3.eth.getBlock(blockNumber)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
const { toBN } = require('web3').utils
|
const { toBN } = require('web3').utils
|
||||||
|
|
||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data)
|
const { 0: address, 1: slot } = web3.eth.abi.decodeParameters(['address', 'bytes32'], data)
|
||||||
|
|
||||||
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
|
|||||||
const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data)
|
const { 0: address, 1: slot, 2: blockNumber } = web3.eth.abi.decodeParameters(['address', 'bytes32', 'uint256'], data)
|
||||||
|
|
||||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = await web3.eth.getStorageAt(address, slot, blockNumber)
|
const value = await web3.eth.getStorageAt(address, slot, blockNumber)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
const { serializeTx } = require('./serializers')
|
const { serializeTx } = require('./serializers')
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
|
|||||||
const tx = await web3.eth.getTransaction(hash)
|
const tx = await web3.eth.getTransaction(hash)
|
||||||
|
|
||||||
if (tx === null || tx.blockNumber > foreignBlock.number) {
|
if (tx === null || tx.blockNumber > foreignBlock.number) {
|
||||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
return [true, serializeTx(web3, tx)]
|
return [true, serializeTx(web3, tx)]
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
const { toBN } = require('web3').utils
|
const { toBN } = require('web3').utils
|
||||||
|
|
||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
const address = web3.eth.abi.decodeParameter('address', data)
|
const address = web3.eth.abi.decodeParameter('address', data)
|
||||||
|
|
||||||
@@ -14,7 +12,7 @@ async function callArchive(web3, data, foreignBlock) {
|
|||||||
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
const { 0: address, 1: blockNumber } = web3.eth.abi.decodeParameters(['address', 'uint256'], data)
|
||||||
|
|
||||||
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
if (toBN(blockNumber).gt(toBN(foreignBlock.number))) {
|
||||||
return [false, ASYNC_CALL_ERRORS.BLOCK_IS_IN_THE_FUTURE]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
const nonce = await web3.eth.getTransactionCount(address, blockNumber)
|
const nonce = await web3.eth.getTransactionCount(address, blockNumber)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const { ASYNC_CALL_ERRORS } = require('../../../utils/constants')
|
|
||||||
const { serializeReceipt } = require('./serializers')
|
const { serializeReceipt } = require('./serializers')
|
||||||
|
|
||||||
async function call(web3, data, foreignBlock) {
|
async function call(web3, data, foreignBlock) {
|
||||||
@@ -7,7 +6,7 @@ async function call(web3, data, foreignBlock) {
|
|||||||
const receipt = await web3.eth.getTransactionReceipt(hash)
|
const receipt = await web3.eth.getTransactionReceipt(hash)
|
||||||
|
|
||||||
if (receipt === null || receipt.blockNumber > foreignBlock.number) {
|
if (receipt === null || receipt.blockNumber > foreignBlock.number) {
|
||||||
return [false, ASYNC_CALL_ERRORS.NOT_FOUND]
|
return [false, '0x']
|
||||||
}
|
}
|
||||||
|
|
||||||
return [true, serializeReceipt(web3, receipt)]
|
return [true, serializeReceipt(web3, receipt)]
|
||||||
|
|||||||
@@ -1,30 +1,15 @@
|
|||||||
const { ZERO_ADDRESS } = require('../../../../../commons')
|
const { ZERO_ADDRESS } = require('../../../../../commons')
|
||||||
|
|
||||||
const serializeBlock = (web3, block) => {
|
const serializeBlock = (web3, block) => {
|
||||||
const args = [
|
const args = [block.number, block.hash, block.miner]
|
||||||
block.number,
|
const types = ['uint256', 'bytes32', 'address']
|
||||||
block.hash,
|
return web3.eth.abi.encodeParameters(types, args)
|
||||||
block.miner,
|
|
||||||
block.gasUsed,
|
|
||||||
block.gasLimit,
|
|
||||||
block.parentHash,
|
|
||||||
block.receiptsRoot,
|
|
||||||
block.stateRoot,
|
|
||||||
block.transactionsRoot,
|
|
||||||
block.timestamp,
|
|
||||||
block.difficulty,
|
|
||||||
block.totalDifficulty
|
|
||||||
]
|
|
||||||
const type = '(uint256,bytes32,address,uint256,uint256,bytes32,bytes32,bytes32,bytes32,uint256,uint256,uint256)'
|
|
||||||
return web3.eth.abi.encodeParameter(type, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const serializeTx = (web3, tx) => {
|
const serializeTx = (web3, tx) => {
|
||||||
const args = [
|
const args = [
|
||||||
tx.hash,
|
tx.hash,
|
||||||
tx.blockNumber,
|
tx.blockNumber,
|
||||||
tx.blockHash,
|
|
||||||
tx.transactionIndex,
|
|
||||||
tx.from,
|
tx.from,
|
||||||
tx.to || ZERO_ADDRESS,
|
tx.to || ZERO_ADDRESS,
|
||||||
tx.value,
|
tx.value,
|
||||||
@@ -33,26 +18,16 @@ const serializeTx = (web3, tx) => {
|
|||||||
tx.gasPrice,
|
tx.gasPrice,
|
||||||
tx.input
|
tx.input
|
||||||
]
|
]
|
||||||
const type = '(bytes32,uint256,bytes32,uint256,address,address,uint256,uint256,uint256,uint256,bytes)'
|
const types = ['bytes32', 'uint256', 'address', 'address', 'uint256', 'uint256', 'uint256', 'uint256', 'bytes']
|
||||||
return web3.eth.abi.encodeParameter(type, args)
|
return web3.eth.abi.encodeParameters(types, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeLog = log => [log.address, log.topics, log.data]
|
const normalizeLog = log => [log.address, log.topics, log.data]
|
||||||
|
|
||||||
const serializeReceipt = (web3, receipt) => {
|
const serializeReceipt = (web3, receipt) => {
|
||||||
const args = [
|
const args = [receipt.transactionHash, receipt.blockNumber, receipt.status, receipt.logs.map(normalizeLog)]
|
||||||
receipt.transactionHash,
|
const types = ['bytes32', 'uint256', 'bool', '(address,bytes32[],bytes)[]']
|
||||||
receipt.blockNumber,
|
return web3.eth.abi.encodeParameters(types, args)
|
||||||
receipt.blockHash,
|
|
||||||
receipt.transactionIndex,
|
|
||||||
receipt.from,
|
|
||||||
receipt.to || ZERO_ADDRESS,
|
|
||||||
receipt.gasUsed,
|
|
||||||
receipt.status,
|
|
||||||
receipt.logs.map(normalizeLog)
|
|
||||||
]
|
|
||||||
const type = '(bytes32,uint256,bytes32,uint256,address,address,uint256,bool,(address,bytes32[],bytes)[])'
|
|
||||||
return web3.eth.abi.encodeParameter(type, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -6,16 +6,7 @@ const logger = require('../../services/logger').child({
|
|||||||
const { strip0x } = require('../../../../commons')
|
const { strip0x } = require('../../../../commons')
|
||||||
const { AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: estimateExtraGas } = require('../../utils/constants')
|
const { AMB_AFFIRMATION_REQUEST_EXTRA_GAS_ESTIMATOR: estimateExtraGas } = require('../../utils/constants')
|
||||||
|
|
||||||
async function estimateGas({
|
async function estimateGas({ web3, homeBridge, validatorContract, messageId, status, result, address }) {
|
||||||
web3,
|
|
||||||
homeBridge,
|
|
||||||
validatorContract,
|
|
||||||
messageId,
|
|
||||||
status,
|
|
||||||
result,
|
|
||||||
address,
|
|
||||||
homeBlockNumber
|
|
||||||
}) {
|
|
||||||
try {
|
try {
|
||||||
const gasEstimate = await homeBridge.methods.confirmInformation(messageId, status, result).estimateGas({
|
const gasEstimate = await homeBridge.methods.confirmInformation(messageId, status, result).estimateGas({
|
||||||
from: address
|
from: address
|
||||||
@@ -24,8 +15,7 @@ async function estimateGas({
|
|||||||
// message length in bytes
|
// message length in bytes
|
||||||
const len = strip0x(result).length / 2
|
const len = strip0x(result).length / 2
|
||||||
|
|
||||||
let callbackGasLimit = parseInt(await homeBridge.methods.maxGasPerTx().call(), 10)
|
const callbackGasLimit = parseInt(await homeBridge.methods.maxGasPerTx().call(), 10)
|
||||||
callbackGasLimit = Math.ceil((callbackGasLimit * 64) / 63)
|
|
||||||
|
|
||||||
return gasEstimate + callbackGasLimit + estimateExtraGas(len)
|
return gasEstimate + callbackGasLimit + estimateExtraGas(len)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -61,20 +51,6 @@ async function estimateGas({
|
|||||||
throw new InvalidValidatorError(`${address} is not a validator`)
|
throw new InvalidValidatorError(`${address} is not a validator`)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug('Check if InformationRetrieved event for this message already exists')
|
|
||||||
const logs = await homeBridge.getPastEvents('InformationRetrieved', {
|
|
||||||
fromBlock: homeBlockNumber,
|
|
||||||
toBlock: 'latest',
|
|
||||||
filter: { messageId }
|
|
||||||
})
|
|
||||||
if (logs.length > 0) {
|
|
||||||
logger.warn(
|
|
||||||
'This particular message was already signed and processed by other validators.' +
|
|
||||||
'However, evaluated async call result is different from the one recorded on-chain.'
|
|
||||||
)
|
|
||||||
throw new AlreadyProcessedError(e.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Unknown error while processing message')
|
throw new Error('Unknown error while processing message')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,7 @@ const { soliditySha3 } = require('web3').utils
|
|||||||
const { HttpListProviderError } = require('../../services/HttpListProvider')
|
const { HttpListProviderError } = require('../../services/HttpListProvider')
|
||||||
const rootLogger = require('../../services/logger')
|
const rootLogger = require('../../services/logger')
|
||||||
const makeBlockFinder = require('../../services/blockFinder')
|
const makeBlockFinder = require('../../services/blockFinder')
|
||||||
const {
|
const { EXIT_CODES, MAX_CONCURRENT_EVENTS, EXTRA_GAS_ABSOLUTE } = require('../../utils/constants')
|
||||||
EXIT_CODES,
|
|
||||||
MAX_CONCURRENT_EVENTS,
|
|
||||||
EXTRA_GAS_ABSOLUTE,
|
|
||||||
ASYNC_CALL_ERRORS,
|
|
||||||
MAX_ASYNC_CALL_RESULT_LENGTH
|
|
||||||
} = require('../../utils/constants')
|
|
||||||
const estimateGas = require('./estimateGas')
|
const estimateGas = require('./estimateGas')
|
||||||
const { getValidatorContract, getBlock, getBlockNumber, getRequiredBlockConfirmations } = require('../../tx/web3')
|
const { getValidatorContract, getBlock, getBlockNumber, getRequiredBlockConfirmations } = require('../../tx/web3')
|
||||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
@@ -85,17 +79,12 @@ function processInformationRequestsBuilder(config) {
|
|||||||
logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request')
|
logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request')
|
||||||
|
|
||||||
const call = asyncCalls[asyncCallMethod]
|
const call = asyncCalls[asyncCallMethod]
|
||||||
let [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => {
|
const [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => {
|
||||||
if (e instanceof HttpListProviderError) {
|
if (e instanceof HttpListProviderError) {
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
logger.error({ error: e.message }, 'Unknown error during async call execution')
|
return [false, '0x']
|
||||||
throw e
|
|
||||||
})
|
})
|
||||||
if (result.length > 2 + MAX_ASYNC_CALL_RESULT_LENGTH * 2) {
|
|
||||||
status = false
|
|
||||||
result = ASYNC_CALL_ERRORS.RESULT_IS_TOO_LONG
|
|
||||||
}
|
|
||||||
logger.info({ requestSelector, method: asyncCallMethod, status, result }, 'Request result obtained')
|
logger.info({ requestSelector, method: asyncCallMethod, status, result }, 'Request result obtained')
|
||||||
|
|
||||||
let gasEstimate
|
let gasEstimate
|
||||||
@@ -108,8 +97,7 @@ function processInformationRequestsBuilder(config) {
|
|||||||
messageId,
|
messageId,
|
||||||
status,
|
status,
|
||||||
result,
|
result,
|
||||||
address: config.validatorAddress,
|
address: config.validatorAddress
|
||||||
homeBlockNumber: homeBlock.number
|
|
||||||
})
|
})
|
||||||
logger.debug({ gasEstimate }, 'Gas estimated')
|
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const estimateGas = require('../processSignatureRequests/estimateGas')
|
|||||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||||
|
|
||||||
|
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
||||||
|
|
||||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||||
|
|
||||||
function processSignatureRequestsBuilder(config) {
|
function processSignatureRequestsBuilder(config) {
|
||||||
@@ -35,7 +37,7 @@ function processSignatureRequestsBuilder(config) {
|
|||||||
const { sender, executor } = parseAMBMessage(message)
|
const { sender, executor } = parseAMBMessage(message)
|
||||||
logger.info({ sender, executor }, `Processing signatureRequest ${messageId}`)
|
logger.info({ sender, executor }, `Processing signatureRequest ${messageId}`)
|
||||||
|
|
||||||
const signature = web3.eth.accounts.sign(message, config.validatorPrivateKey)
|
const signature = web3.eth.accounts.sign(message, `0x${ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY}`)
|
||||||
|
|
||||||
let gasEstimate
|
let gasEstimate
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ const estimateGas = require('./estimateGas')
|
|||||||
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
const { AlreadyProcessedError, AlreadySignedError, InvalidValidatorError } = require('../../utils/errors')
|
||||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||||
|
|
||||||
|
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
||||||
|
|
||||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||||
|
|
||||||
function processSignatureRequestsBuilder(config) {
|
function processSignatureRequestsBuilder(config) {
|
||||||
@@ -46,7 +48,7 @@ function processSignatureRequestsBuilder(config) {
|
|||||||
expectedMessageLength
|
expectedMessageLength
|
||||||
})
|
})
|
||||||
|
|
||||||
const signature = web3.eth.accounts.sign(message, config.validatorPrivateKey)
|
const signature = web3.eth.accounts.sign(message, `0x${ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY}`)
|
||||||
|
|
||||||
let gasEstimate
|
let gasEstimate
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -13,25 +13,12 @@ const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
|||||||
function processTransfersBuilder(config) {
|
function processTransfersBuilder(config) {
|
||||||
const { bridgeContract, web3 } = config.home
|
const { bridgeContract, web3 } = config.home
|
||||||
|
|
||||||
const userRequestForAffirmationHash = web3.eth.abi.encodeEventSignature('UserRequestForAffirmation(address,uint256)')
|
const userRequestForAffirmationAbi = config.foreign.bridgeABI.find(
|
||||||
const redeemHash = web3.eth.abi.encodeEventSignature('Redeem(address,uint256,uint256)')
|
e => e.type === 'event' && e.name === 'UserRequestForAffirmation'
|
||||||
const transferHash = web3.eth.abi.encodeEventSignature('Transfer(address,address,uint256)')
|
)
|
||||||
|
const tokensSwappedAbi = config.foreign.bridgeABI.find(e => e.type === 'event' && e.name === 'TokensSwapped')
|
||||||
const foreignBridgeAddress = config.foreign.bridgeAddress
|
const userRequestForAffirmationHash = web3.eth.abi.encodeEventSignature(userRequestForAffirmationAbi)
|
||||||
|
const tokensSwappedHash = tokensSwappedAbi ? web3.eth.abi.encodeEventSignature(tokensSwappedAbi) : '0x'
|
||||||
const decodeAddress = data => web3.eth.abi.decodeParameter('address', data)
|
|
||||||
|
|
||||||
const isUserRequestForAffirmation = e =>
|
|
||||||
e.address.toLowerCase() === foreignBridgeAddress.toLowerCase() && e.topics[0] === userRequestForAffirmationHash
|
|
||||||
const isRedeem = cTokenAddress => e =>
|
|
||||||
e.address.toLowerCase() === cTokenAddress.toLowerCase() &&
|
|
||||||
e.topics[0] === redeemHash &&
|
|
||||||
decodeAddress(e.data.slice(0, 66)).toLowerCase() === foreignBridgeAddress.toLowerCase()
|
|
||||||
const isCTokenTransfer = cTokenAddress => e =>
|
|
||||||
e.address.toLowerCase() === cTokenAddress.toLowerCase() &&
|
|
||||||
e.topics[0] === transferHash &&
|
|
||||||
decodeAddress(e.topics[1]).toLowerCase() === foreignBridgeAddress.toLowerCase() &&
|
|
||||||
decodeAddress(e.topics[2]).toLowerCase() === cTokenAddress.toLowerCase()
|
|
||||||
|
|
||||||
let validatorContract = null
|
let validatorContract = null
|
||||||
|
|
||||||
@@ -45,35 +32,37 @@ function processTransfersBuilder(config) {
|
|||||||
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
|
rootLogger.debug(`Processing ${transfers.length} Transfer events`)
|
||||||
const callbacks = transfers
|
const callbacks = transfers
|
||||||
.map(transfer => async () => {
|
.map(transfer => async () => {
|
||||||
const { from, to, value } = transfer.returnValues
|
const { from, value } = transfer.returnValues
|
||||||
|
|
||||||
const logger = rootLogger.child({
|
const logger = rootLogger.child({
|
||||||
eventTransactionHash: transfer.transactionHash,
|
eventTransactionHash: transfer.transactionHash
|
||||||
from,
|
|
||||||
to,
|
|
||||||
value
|
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info('Processing transfer')
|
logger.info({ from, value }, `Processing transfer ${transfer.transactionHash}`)
|
||||||
|
|
||||||
const receipt = await config.foreign.web3.eth.getTransactionReceipt(transfer.transactionHash)
|
const receipt = await config.foreign.web3.eth.getTransactionReceipt(transfer.transactionHash)
|
||||||
|
|
||||||
if (receipt.logs.some(isUserRequestForAffirmation)) {
|
const existsAffirmationEvent = receipt.logs.some(
|
||||||
logger.info('Transfer event discarded because affirmation is detected in the same transaction')
|
e => e.address === config.foreign.bridgeAddress && e.topics[0] === userRequestForAffirmationHash
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existsAffirmationEvent) {
|
||||||
|
logger.info(
|
||||||
|
`Transfer event discarded because a transaction with alternative receiver detected in transaction ${
|
||||||
|
transfer.transactionHash
|
||||||
|
}`
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from === ZERO_ADDRESS) {
|
const existsTokensSwappedEvent = tokensSwappedAbi
|
||||||
logger.info('Mint-like transfers from zero address are not processed')
|
? receipt.logs.some(e => e.address === config.foreign.bridgeAddress && e.topics[0] === tokensSwappedHash)
|
||||||
return
|
: false
|
||||||
}
|
|
||||||
|
|
||||||
// when bridge performs a withdrawal from Compound, the following three events occur
|
if (from === ZERO_ADDRESS && existsTokensSwappedEvent) {
|
||||||
// * token.Transfer(from=cToken, to=bridge, amount=X)
|
logger.info(
|
||||||
// * cToken.Redeem(redeemer=bridge, amount=X, tokens=Y)
|
`Transfer event discarded because token swap is detected in transaction ${transfer.transactionHash}`
|
||||||
// * cToken.Transfer(from=bridge, to=cToken, amount=Y)
|
)
|
||||||
if (receipt.logs.some(isRedeem(from)) && receipt.logs.some(isCTokenTransfer(from))) {
|
|
||||||
logger.info('Transfer event discarded because cToken redeem is detected in the same transaction')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,18 +10,18 @@ const { getNonce, getChainId } = require('./tx/web3')
|
|||||||
const {
|
const {
|
||||||
addExtraGas,
|
addExtraGas,
|
||||||
checkHTTPS,
|
checkHTTPS,
|
||||||
|
privateKeyToAddress,
|
||||||
syncForEach,
|
syncForEach,
|
||||||
waitForFunds,
|
waitForFunds,
|
||||||
waitForUnsuspend,
|
waitForUnsuspend,
|
||||||
watchdog,
|
watchdog,
|
||||||
isGasPriceError,
|
nonceError
|
||||||
isSameTransactionError,
|
|
||||||
isInsufficientBalanceError,
|
|
||||||
isNonceError
|
|
||||||
} = require('./utils/utils')
|
} = require('./utils/utils')
|
||||||
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
const { EXIT_CODES, EXTRA_GAS_PERCENTAGE, MAX_GAS_LIMIT } = require('./utils/constants')
|
||||||
|
|
||||||
const { ORACLE_TX_REDUNDANCY } = process.env
|
const { ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY, ORACLE_TX_REDUNDANCY } = process.env
|
||||||
|
|
||||||
|
const ORACLE_VALIDATOR_ADDRESS = privateKeyToAddress(ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY)
|
||||||
|
|
||||||
if (process.argv.length < 3) {
|
if (process.argv.length < 3) {
|
||||||
logger.error('Please check the number of arguments, config file was not provided')
|
logger.error('Please check the number of arguments, config file was not provided')
|
||||||
@@ -40,7 +40,7 @@ async function initialize() {
|
|||||||
try {
|
try {
|
||||||
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
|
||||||
|
|
||||||
web3.currentProvider.urls.forEach(checkHttps(config.id))
|
web3.currentProvider.urls.forEach(checkHttps(config.chain))
|
||||||
|
|
||||||
GasPrice.start(config.id)
|
GasPrice.start(config.id)
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ async function readNonce(forceUpdate) {
|
|||||||
logger.debug('Reading nonce')
|
logger.debug('Reading nonce')
|
||||||
if (forceUpdate) {
|
if (forceUpdate) {
|
||||||
logger.debug('Forcing update of nonce')
|
logger.debug('Forcing update of nonce')
|
||||||
return getNonce(web3, config.validatorAddress)
|
return getNonce(web3, ORACLE_VALIDATOR_ADDRESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
const nonce = await redis.get(nonceKey)
|
const nonce = await redis.get(nonceKey)
|
||||||
@@ -93,7 +93,7 @@ async function readNonce(forceUpdate) {
|
|||||||
return Number(nonce)
|
return Number(nonce)
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Nonce wasn't found in the DB")
|
logger.warn("Nonce wasn't found in the DB")
|
||||||
return getNonce(web3, config.validatorAddress)
|
return getNonce(web3, ORACLE_VALIDATOR_ADDRESS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
gasPrice,
|
gasPrice,
|
||||||
amount: '0',
|
amount: '0',
|
||||||
gasLimit,
|
gasLimit,
|
||||||
privateKey: config.validatorPrivateKey,
|
privateKey: ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||||
to: job.to,
|
to: job.to,
|
||||||
chainId,
|
chainId,
|
||||||
web3: web3Redundant
|
web3: web3Redundant
|
||||||
@@ -192,11 +192,12 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
e.message
|
e.message
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isGasPriceError(e)) {
|
const message = e.message.toLowerCase()
|
||||||
|
if (message.includes('replacement transaction underpriced')) {
|
||||||
logger.info('Replacement transaction underpriced, forcing gas price update')
|
logger.info('Replacement transaction underpriced, forcing gas price update')
|
||||||
GasPrice.start(config.id)
|
GasPrice.start(config.id)
|
||||||
failedTx.push(job)
|
failedTx.push(job)
|
||||||
} else if (isResend || isSameTransactionError(e)) {
|
} else if (isResend || message.includes('transaction with the same hash was already imported')) {
|
||||||
resendJobs.push(job)
|
resendJobs.push(job)
|
||||||
} else {
|
} else {
|
||||||
// if initial transaction sending has failed not due to the same hash error
|
// if initial transaction sending has failed not due to the same hash error
|
||||||
@@ -205,14 +206,14 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
failedTx.push(job)
|
failedTx.push(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInsufficientBalanceError(e)) {
|
if (message.includes('insufficient funds')) {
|
||||||
insufficientFunds = true
|
insufficientFunds = true
|
||||||
const currentBalance = await web3.eth.getBalance(config.validatorAddress)
|
const currentBalance = await web3.eth.getBalance(ORACLE_VALIDATOR_ADDRESS)
|
||||||
minimumBalance = gasLimit.multipliedBy(gasPrice)
|
minimumBalance = gasLimit.multipliedBy(gasPrice)
|
||||||
logger.error(
|
logger.error(
|
||||||
`Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.`
|
`Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.`
|
||||||
)
|
)
|
||||||
} else if (isNonceError(e)) {
|
} else if (nonceError(e)) {
|
||||||
nonce = await readNonce(true)
|
nonce = await readNonce(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,7 +238,7 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
if (insufficientFunds) {
|
if (insufficientFunds) {
|
||||||
logger.warn('Insufficient funds. Stop sending transactions until the account has the minimum balance')
|
logger.warn('Insufficient funds. Stop sending transactions until the account has the minimum balance')
|
||||||
channel.close()
|
channel.close()
|
||||||
waitForFunds(web3, config.validatorAddress, minimumBalance, resume, logger)
|
waitForFunds(web3, ORACLE_VALIDATOR_ADDRESS, minimumBalance, resume, logger)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|||||||
@@ -2,14 +2,8 @@ const fetch = require('node-fetch')
|
|||||||
const promiseRetry = require('promise-retry')
|
const promiseRetry = require('promise-retry')
|
||||||
const { FALLBACK_RPC_URL_SWITCH_TIMEOUT } = require('../utils/constants')
|
const { FALLBACK_RPC_URL_SWITCH_TIMEOUT } = require('../utils/constants')
|
||||||
|
|
||||||
const { onInjected } = require('./injectedLogger')
|
|
||||||
|
|
||||||
const { ORACLE_JSONRPC_ERROR_CODES } = process.env
|
|
||||||
|
|
||||||
// From EIP-1474 and Infura documentation
|
// From EIP-1474 and Infura documentation
|
||||||
const JSONRPC_ERROR_CODES = ORACLE_JSONRPC_ERROR_CODES
|
const JSONRPC_ERROR_CODES = [-32603, -32002, -32005]
|
||||||
? ORACLE_JSONRPC_ERROR_CODES.split(',').map(s => parseInt(s, 10))
|
|
||||||
: [-32603, -32002, -32005]
|
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
name: 'main',
|
name: 'main',
|
||||||
@@ -39,24 +33,14 @@ function HttpListProvider(urls, options = {}) {
|
|||||||
this.options = { ...defaultOptions, ...options }
|
this.options = { ...defaultOptions, ...options }
|
||||||
this.currentIndex = 0
|
this.currentIndex = 0
|
||||||
this.lastTimeUsedPrimary = 0
|
this.lastTimeUsedPrimary = 0
|
||||||
|
this.logger = {
|
||||||
onInjected(logger => {
|
debug: () => {},
|
||||||
this.logger = logger.child({ module: `HttpListProvider:${this.options.name}` })
|
info: () => {}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpListProvider.prototype.switchToFallbackRPC = function() {
|
HttpListProvider.prototype.setLogger = function(logger) {
|
||||||
if (this.urls.length < 2) {
|
this.logger = logger.child({ module: `HttpListProvider:${this.options.name}` })
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const prevIndex = this.currentIndex
|
|
||||||
const newIndex = (prevIndex + 1) % this.urls.length
|
|
||||||
this.logger.info(
|
|
||||||
{ index: newIndex, oldURL: this.urls[prevIndex], newURL: this.urls[newIndex] },
|
|
||||||
'Switching to fallback JSON-RPC URL'
|
|
||||||
)
|
|
||||||
this.currentIndex = newIndex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpListProvider.prototype.send = async function send(payload, callback) {
|
HttpListProvider.prototype.send = async function send(payload, callback) {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
const promiseRetry = require('promise-retry')
|
const promiseRetry = require('promise-retry')
|
||||||
const { promiseAny } = require('../utils/utils')
|
const { promiseAny } = require('../utils/utils')
|
||||||
const { defaultOptions, HttpListProviderError, send } = require('./HttpListProvider')
|
const { defaultOptions, HttpListProviderError, send } = require('./HttpListProvider')
|
||||||
const { onInjected } = require('./injectedLogger')
|
|
||||||
|
|
||||||
function RedundantHttpListProvider(urls, options = {}) {
|
function RedundantHttpListProvider(urls, options = {}) {
|
||||||
if (!(this instanceof RedundantHttpListProvider)) {
|
if (!(this instanceof RedundantHttpListProvider)) {
|
||||||
@@ -14,9 +13,10 @@ function RedundantHttpListProvider(urls, options = {}) {
|
|||||||
|
|
||||||
this.urls = urls
|
this.urls = urls
|
||||||
this.options = { ...defaultOptions, ...options }
|
this.options = { ...defaultOptions, ...options }
|
||||||
onInjected(logger => {
|
}
|
||||||
|
|
||||||
|
RedundantHttpListProvider.prototype.setLogger = function(logger) {
|
||||||
this.logger = logger.child({ module: `RedundantHttpListProvider:${this.options.name}` })
|
this.logger = logger.child({ module: `RedundantHttpListProvider:${this.options.name}` })
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RedundantHttpListProvider.prototype.send = async function send(payload, callback) {
|
RedundantHttpListProvider.prototype.send = async function send(payload, callback) {
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
const { hexToNumber, isHexStrict } = require('web3').utils
|
|
||||||
|
|
||||||
function SafeEthLogsProvider(provider) {
|
|
||||||
const oldSend = provider.send.bind(provider)
|
|
||||||
const newSend = function(payload, callback) {
|
|
||||||
if (payload.method === 'eth_getLogs' && isHexStrict(payload.params[0].toBlock)) {
|
|
||||||
this.logger.debug('Modifying eth_getLogs request to include batch eth_blockNumber request')
|
|
||||||
|
|
||||||
const newPayload = [payload, { jsonrpc: '2.0', id: payload.id + 1, method: 'eth_blockNumber', params: [] }]
|
|
||||||
oldSend(newPayload, (err, res) => {
|
|
||||||
if (err) {
|
|
||||||
callback(err, null)
|
|
||||||
} else {
|
|
||||||
const rawLogs = res.find(({ id }) => id === payload.id)
|
|
||||||
const rawBlockNumber = res.find(({ id }) => id === payload.id + 1)
|
|
||||||
const blockNumber = hexToNumber(rawBlockNumber.result)
|
|
||||||
const toBlock = hexToNumber(payload.params[0].toBlock)
|
|
||||||
|
|
||||||
if (blockNumber < toBlock) {
|
|
||||||
this.logger.warn({ toBlock, blockNumber }, 'Returned block number is less than the specified toBlock')
|
|
||||||
callback(new Error('block number too low'), null)
|
|
||||||
} else {
|
|
||||||
callback(null, rawLogs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
oldSend(payload, callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
provider.send = newSend.bind(provider)
|
|
||||||
return provider
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
SafeEthLogsProvider
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user