add amb base implementation on oracle
This commit is contained in:
parent
94e923d965
commit
7ca3b0079c
682
oracle/abis/ForeignAMB.abi.json
Normal file
682
oracle/abis/ForeignAMB.abi.json
Normal file
@ -0,0 +1,682 @@
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_oracleGasPriceSpeed",
|
||||
"type": "bytes1"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "depositForContractSender",
|
||||
"outputs": [],
|
||||
"payable": true,
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_txHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "relayedMessages",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_day",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "totalSpentPerDay",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "isInitialized",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setDefrayalModeForHomeToForeign",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentDay",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "requiredBlockConfirmations",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "getMinimumGasUsage",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "gas",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBridgeMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setSubsidizedModeForForeignToHome",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_validatorContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_maxGasPerTx",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_requiredBlockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "vs",
|
||||
"type": "uint8[]"
|
||||
},
|
||||
{
|
||||
"name": "rs",
|
||||
"type": "bytes32[]"
|
||||
},
|
||||
{
|
||||
"name": "ss",
|
||||
"type": "bytes32[]"
|
||||
}
|
||||
],
|
||||
"name": "executeSignatures",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "dailyLimit",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "claimTokens",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "homeToForeignMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_balanceHolder",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_maxGasPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMaxGasPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "withdrawFromDeposit",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setSubsidizedModeForHomeToForeign",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "requiredSignatures",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "foreignToHomeMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setDefrayalModeForForeignToHome",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "validatorContract",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "deployedAtBlock",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBridgeInterfacesVersion",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "major",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "minor",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "patch",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_minPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMinPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_blockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setRequiredBlockConfirmations",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_dailyLimit",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setDailyLimit",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setGasPrice",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_maxPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMaxPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "minPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "maxGasPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "withinLimit",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "maxPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "gasPrice",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "encodedData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "UserRequestForAffirmation",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "executor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "transactionHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "RelayedMessage",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "GasPriceChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "requiredBlockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "RequiredBlockConfirmationChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "newLimit",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "DailyLimitChanged",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
862
oracle/abis/HomeAMB.abi.json
Normal file
862
oracle/abis/HomeAMB.abi.json
Normal file
@ -0,0 +1,862 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_message",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "numMessagesSigned",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_oracleGasPriceSpeed",
|
||||
"type": "bytes1"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "depositForContractSender",
|
||||
"outputs": [],
|
||||
"payable": true,
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_hash",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"name": "_index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "signature",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_day",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "totalSpentPerDay",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "isInitialized",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setDefrayalModeForHomeToForeign",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentDay",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "requiredBlockConfirmations",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "getMinimumGasUsage",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "gas",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBridgeMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_hash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "message",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setSubsidizedModeForForeignToHome",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_validatorContract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_maxGasPerTx",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_requiredBlockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "signature",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "message",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "submitSignature",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "dailyLimit",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "claimTokens",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_hash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "numAffirmationsSigned",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "homeToForeignMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_balanceHolder",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_hash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "affirmationsSigned",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_maxGasPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMaxGasPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "withdrawFromDeposit",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setSubsidizedModeForHomeToForeign",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "requiredSignatures",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_message",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "messagesSigned",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "foreignToHomeMode",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "setDefrayalModeForForeignToHome",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "validatorContract",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "deployedAtBlock",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getBridgeInterfacesVersion",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "major",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "minor",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "patch",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_minPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMinPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_blockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setRequiredBlockConfirmations",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_dailyLimit",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setDailyLimit",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setGasPrice",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_maxPerTx",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setMaxPerTx",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "minPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "maxGasPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "message",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "executeAffirmation",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_contract",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
},
|
||||
{
|
||||
"name": "_gas",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "_gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "requireToPassMessage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "withinLimit",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "maxPerTx",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "gasPrice",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "_number",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "isAlreadyProcessed",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "pure",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "encodedData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "UserRequestForSignature",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "executor",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "txHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "AffirmationCompleted",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "signer",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "messageHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "SignedForUserRequest",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "signer",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "messageHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "SignedForAffirmation",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "authorityResponsibleForRelay",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "messageHash",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "NumberOfCollectedSignatures",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "CollectedSignatures",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "gasPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "GasPriceChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "requiredBlockConfirmations",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "RequiredBlockConfirmationChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "newLimit",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "DailyLimitChanged",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
@ -13,6 +13,9 @@ const foreignErc677Erc677Abi = require('../abis/ForeignBridgeErc677ToErc677.abi'
|
||||
const homeErcNativeAbi = require('../abis/HomeBridgeErcToNative.abi')
|
||||
const foreignErcNativeAbi = require('../abis/ForeignBridgeErcToNative.abi')
|
||||
|
||||
const homeAMBAbi = require('../abis/HomeAMB.abi')
|
||||
const foreignAMBAbi = require('../abis/ForeignAMB.abi')
|
||||
|
||||
const { VALIDATOR_ADDRESS, VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
||||
|
||||
let homeAbi
|
||||
@ -35,6 +38,11 @@ switch (process.env.BRIDGE_MODE) {
|
||||
foreignAbi = foreignErcNativeAbi
|
||||
id = 'erc-native'
|
||||
break
|
||||
case 'ARBITRARY_MESSAGE':
|
||||
homeAbi = homeAMBAbi
|
||||
foreignAbi = foreignAMBAbi
|
||||
id = 'amb'
|
||||
break
|
||||
default:
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
throw new Error(`Bridge Mode: ${process.env.BRIDGE_MODE} not supported.`)
|
||||
|
@ -0,0 +1,57 @@
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const {
|
||||
AlreadyProcessedError,
|
||||
AlreadySignedError,
|
||||
InvalidValidatorError
|
||||
} = require('../../utils/errors')
|
||||
const logger = require('../../services/logger').child({
|
||||
module: 'processAffirmationRequests:estimateGas'
|
||||
})
|
||||
|
||||
async function estimateGas({ web3, homeBridge, validatorContract, message, address }) {
|
||||
try {
|
||||
const gasEstimate = await homeBridge.methods.executeAffirmation(message).estimateGas({
|
||||
from: address
|
||||
})
|
||||
|
||||
return gasEstimate
|
||||
} catch (e) {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw e
|
||||
}
|
||||
|
||||
const messageHash = web3.utils.soliditySha3(message)
|
||||
const senderHash = web3.utils.soliditySha3(address, messageHash)
|
||||
|
||||
// Check if minimum number of validations was already reached
|
||||
logger.debug('Check if minimum number of validations was already reached')
|
||||
const numAffirmationsSigned = await homeBridge.methods.numAffirmationsSigned(messageHash).call()
|
||||
const alreadyProcessed = await homeBridge.methods
|
||||
.isAlreadyProcessed(numAffirmationsSigned)
|
||||
.call()
|
||||
|
||||
if (alreadyProcessed) {
|
||||
throw new AlreadyProcessedError(e.message)
|
||||
}
|
||||
|
||||
// Check if the message was already signed by this validator
|
||||
logger.debug('Check if the message was already signed')
|
||||
const alreadySigned = await homeBridge.methods.affirmationsSigned(senderHash).call()
|
||||
|
||||
if (alreadySigned) {
|
||||
throw new AlreadySignedError(e.message)
|
||||
}
|
||||
|
||||
// Check if address is validator
|
||||
logger.debug('Check if address is a validator')
|
||||
const isValidator = await validatorContract.methods.isValidator(address).call()
|
||||
|
||||
if (!isValidator) {
|
||||
throw new InvalidValidatorError(`${address} is not a validator`)
|
||||
}
|
||||
|
||||
throw new Error('Unknown error while processing message')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = estimateGas
|
110
oracle/src/events/processAMBAffirmationRequests/index.js
Normal file
110
oracle/src/events/processAMBAffirmationRequests/index.js
Normal file
@ -0,0 +1,110 @@
|
||||
require('dotenv').config()
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const promiseLimit = require('promise-limit')
|
||||
const rootLogger = require('../../services/logger')
|
||||
const { web3Home } = require('../../services/web3')
|
||||
const bridgeValidatorsABI = require('../../../abis/BridgeValidators.abi')
|
||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||
const estimateGas = require('./estimateGas')
|
||||
const { addTxHashToData, parseAMBMessage } = require('../../utils/message')
|
||||
const { generateGasPriceOptions } = require('../../utils/utils')
|
||||
const {
|
||||
AlreadyProcessedError,
|
||||
AlreadySignedError,
|
||||
InvalidValidatorError
|
||||
} = require('../../utils/errors')
|
||||
|
||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||
|
||||
let validatorContract = null
|
||||
|
||||
function processAffirmationRequestsBuilder(config) {
|
||||
const homeBridge = new web3Home.eth.Contract(config.homeBridgeAbi, config.homeBridgeAddress)
|
||||
|
||||
return async function processAffirmationRequests(affirmationRequests) {
|
||||
const txToSend = []
|
||||
|
||||
if (validatorContract === null) {
|
||||
rootLogger.debug('Getting validator contract address')
|
||||
const validatorContractAddress = await homeBridge.methods.validatorContract().call()
|
||||
rootLogger.debug({ validatorContractAddress }, 'Validator contract address obtained')
|
||||
|
||||
validatorContract = new web3Home.eth.Contract(bridgeValidatorsABI, validatorContractAddress)
|
||||
}
|
||||
|
||||
rootLogger.debug(`Processing ${affirmationRequests.length} AffirmationRequest events`)
|
||||
const callbacks = affirmationRequests.map(affirmationRequest =>
|
||||
limit(async () => {
|
||||
const { encodedData } = affirmationRequest.returnValues
|
||||
|
||||
const logger = rootLogger.child({
|
||||
eventTransactionHash: affirmationRequest.transactionHash
|
||||
})
|
||||
|
||||
const message = addTxHashToData({
|
||||
encodedData,
|
||||
transactionHash: affirmationRequest.transactionHash
|
||||
})
|
||||
|
||||
const { sender, executor, dataType, gasPrice, gasPriceSpeed } = parseAMBMessage(message)
|
||||
|
||||
logger.info(
|
||||
{ sender, executor },
|
||||
`Processing affirmationRequest ${affirmationRequest.transactionHash}`
|
||||
)
|
||||
|
||||
let gasEstimate
|
||||
try {
|
||||
logger.debug('Estimate gas')
|
||||
gasEstimate = await estimateGas({
|
||||
web3: web3Home,
|
||||
homeBridge,
|
||||
validatorContract,
|
||||
message,
|
||||
address: config.validatorAddress
|
||||
})
|
||||
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||
} catch (e) {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw new Error(
|
||||
'RPC Connection Error: submitSignature Gas Estimate cannot be obtained.'
|
||||
)
|
||||
} else if (e instanceof InvalidValidatorError) {
|
||||
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
|
||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
||||
} else if (e instanceof AlreadySignedError) {
|
||||
logger.info(`Already signed affirmationRequest ${affirmationRequest.transactionHash}`)
|
||||
return
|
||||
} else if (e instanceof AlreadyProcessedError) {
|
||||
logger.info(
|
||||
`affirmationRequest ${
|
||||
affirmationRequest.transactionHash
|
||||
} was already processed by other validators`
|
||||
)
|
||||
return
|
||||
} else {
|
||||
logger.error(e, 'Unknown error while processing transaction')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const data = await homeBridge.methods.executeAffirmation(message).encodeABI()
|
||||
|
||||
const gasPriceOptions = generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed })
|
||||
|
||||
txToSend.push({
|
||||
data,
|
||||
gasEstimate,
|
||||
transactionReference: affirmationRequest.transactionHash,
|
||||
to: config.homeBridgeAddress,
|
||||
gasPriceOptions
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
await Promise.all(callbacks)
|
||||
return txToSend
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processAffirmationRequestsBuilder
|
@ -0,0 +1,67 @@
|
||||
const Web3 = require('web3')
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const {
|
||||
AlreadyProcessedError,
|
||||
IncompatibleContractError,
|
||||
InvalidValidatorError
|
||||
} = require('../../utils/errors')
|
||||
const logger = require('../../services/logger').child({
|
||||
module: 'processCollectedSignatures:estimateGas'
|
||||
})
|
||||
|
||||
const web3 = new Web3()
|
||||
const { toBN } = Web3.utils
|
||||
|
||||
async function estimateGas({
|
||||
foreignBridge,
|
||||
validatorContract,
|
||||
message,
|
||||
numberOfCollectedSignatures,
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
txHash,
|
||||
address
|
||||
}) {
|
||||
try {
|
||||
const gasEstimate = await foreignBridge.methods
|
||||
.executeSignatures(message, v, r, s)
|
||||
.estimateGas({
|
||||
from: address
|
||||
})
|
||||
return gasEstimate
|
||||
} catch (e) {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw e
|
||||
}
|
||||
|
||||
// check if the message was already processed
|
||||
logger.debug('Check if the message was already processed')
|
||||
const alreadyProcessed = await foreignBridge.methods.relayedMessages(txHash).call()
|
||||
if (alreadyProcessed) {
|
||||
throw new AlreadyProcessedError()
|
||||
}
|
||||
|
||||
// check if the number of signatures is enough
|
||||
logger.debug('Check if number of signatures is enough')
|
||||
const requiredSignatures = await validatorContract.methods.requiredSignatures().call()
|
||||
if (toBN(requiredSignatures).gt(toBN(numberOfCollectedSignatures))) {
|
||||
throw new IncompatibleContractError('The number of collected signatures does not match')
|
||||
}
|
||||
|
||||
// check if all the signatures were made by validators
|
||||
for (let i = 0; i < v.length; i++) {
|
||||
const address = web3.eth.accounts.recover(message, web3.utils.toHex(v[i]), r[i], s[i])
|
||||
logger.debug({ address }, 'Check that signature is from a validator')
|
||||
const isValidator = await validatorContract.methods.isValidator(address).call()
|
||||
|
||||
if (!isValidator) {
|
||||
throw new InvalidValidatorError(`Message signed by ${address} that is not a validator`)
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unknown error while processing message')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = estimateGas
|
140
oracle/src/events/processAMBCollectedSignatures/index.js
Normal file
140
oracle/src/events/processAMBCollectedSignatures/index.js
Normal file
@ -0,0 +1,140 @@
|
||||
require('dotenv').config()
|
||||
const promiseLimit = require('promise-limit')
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const bridgeValidatorsABI = require('../../../abis/BridgeValidators.abi')
|
||||
const rootLogger = require('../../services/logger')
|
||||
const { web3Home, web3Foreign } = require('../../services/web3')
|
||||
const { signatureToVRS, parseAMBMessage } = require('../../utils/message')
|
||||
const { generateGasPriceOptions } = require('../../utils/utils')
|
||||
const estimateGas = require('./estimateGas')
|
||||
const {
|
||||
AlreadyProcessedError,
|
||||
IncompatibleContractError,
|
||||
InvalidValidatorError
|
||||
} = require('../../utils/errors')
|
||||
const { MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||
|
||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||
|
||||
let validatorContract = null
|
||||
|
||||
function processCollectedSignaturesBuilder(config) {
|
||||
const homeBridge = new web3Home.eth.Contract(config.homeBridgeAbi, config.homeBridgeAddress)
|
||||
|
||||
const foreignBridge = new web3Foreign.eth.Contract(
|
||||
config.foreignBridgeAbi,
|
||||
config.foreignBridgeAddress
|
||||
)
|
||||
|
||||
return async function processCollectedSignatures(signatures) {
|
||||
const txToSend = []
|
||||
|
||||
if (validatorContract === null) {
|
||||
rootLogger.debug('Getting validator contract address')
|
||||
const validatorContractAddress = await foreignBridge.methods.validatorContract().call()
|
||||
rootLogger.debug({ validatorContractAddress }, 'Validator contract address obtained')
|
||||
|
||||
validatorContract = new web3Foreign.eth.Contract(
|
||||
bridgeValidatorsABI,
|
||||
validatorContractAddress
|
||||
)
|
||||
}
|
||||
|
||||
rootLogger.debug(`Processing ${signatures.length} CollectedSignatures events`)
|
||||
const callbacks = signatures.map(colSignature =>
|
||||
limit(async () => {
|
||||
const {
|
||||
authorityResponsibleForRelay,
|
||||
messageHash,
|
||||
NumberOfCollectedSignatures
|
||||
} = colSignature.returnValues
|
||||
|
||||
const logger = rootLogger.child({
|
||||
eventTransactionHash: colSignature.transactionHash
|
||||
})
|
||||
|
||||
if (
|
||||
authorityResponsibleForRelay === web3Home.utils.toChecksumAddress(config.validatorAddress)
|
||||
) {
|
||||
logger.info(`Processing CollectedSignatures ${colSignature.transactionHash}`)
|
||||
const message = await homeBridge.methods.message(messageHash).call()
|
||||
|
||||
const requiredSignatures = []
|
||||
requiredSignatures.length = NumberOfCollectedSignatures
|
||||
requiredSignatures.fill(0)
|
||||
|
||||
const [v, r, s] = [[], [], []]
|
||||
logger.debug('Getting message signatures')
|
||||
const signaturePromises = requiredSignatures.map(async (el, index) => {
|
||||
logger.debug({ index }, 'Getting message signature')
|
||||
const signature = await homeBridge.methods.signature(messageHash, index).call()
|
||||
const recover = signatureToVRS(signature)
|
||||
v.push(recover.v)
|
||||
r.push(recover.r)
|
||||
s.push(recover.s)
|
||||
})
|
||||
|
||||
await Promise.all(signaturePromises)
|
||||
|
||||
const { dataType, gasPrice, gasPriceSpeed, txHash } = parseAMBMessage(message)
|
||||
|
||||
let gasEstimate
|
||||
try {
|
||||
logger.debug('Estimate gas')
|
||||
gasEstimate = await estimateGas({
|
||||
foreignBridge,
|
||||
validatorContract,
|
||||
v,
|
||||
r,
|
||||
s,
|
||||
message,
|
||||
numberOfCollectedSignatures: NumberOfCollectedSignatures,
|
||||
txHash,
|
||||
address: config.validatorAddress
|
||||
})
|
||||
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||
} catch (e) {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw new Error(
|
||||
'RPC Connection Error: submitSignature Gas Estimate cannot be obtained.'
|
||||
)
|
||||
} else if (e instanceof AlreadyProcessedError) {
|
||||
logger.info(`Already processed CollectedSignatures ${colSignature.transactionHash}`)
|
||||
return
|
||||
} else if (
|
||||
e instanceof IncompatibleContractError ||
|
||||
e instanceof InvalidValidatorError
|
||||
) {
|
||||
logger.error(`The message couldn't be processed; skipping: ${e.message}`)
|
||||
return
|
||||
} else {
|
||||
logger.error(e, 'Unknown error while processing transaction')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
const data = await foreignBridge.methods.executeSignatures(message, v, r, s).encodeABI()
|
||||
const gasPriceOptions = generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed })
|
||||
txToSend.push({
|
||||
data,
|
||||
gasEstimate,
|
||||
transactionReference: colSignature.transactionHash,
|
||||
to: config.foreignBridgeAddress,
|
||||
gasPriceOptions
|
||||
})
|
||||
} else {
|
||||
logger.info(
|
||||
`Validator not responsible for relaying CollectedSignatures ${
|
||||
colSignature.transactionHash
|
||||
}`
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
await Promise.all(callbacks)
|
||||
|
||||
return txToSend
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processCollectedSignaturesBuilder
|
112
oracle/src/events/processAMBSignatureRequests/index.js
Normal file
112
oracle/src/events/processAMBSignatureRequests/index.js
Normal file
@ -0,0 +1,112 @@
|
||||
require('dotenv').config()
|
||||
const promiseLimit = require('promise-limit')
|
||||
const { HttpListProviderError } = require('http-list-provider')
|
||||
const bridgeValidatorsABI = require('../../../abis/BridgeValidators.abi')
|
||||
const rootLogger = require('../../services/logger')
|
||||
const { web3Home } = require('../../services/web3')
|
||||
const { addTxHashToData, parseAMBMessage } = require('../../utils/message')
|
||||
const estimateGas = require('../processSignatureRequests/estimateGas')
|
||||
const {
|
||||
AlreadyProcessedError,
|
||||
AlreadySignedError,
|
||||
InvalidValidatorError
|
||||
} = require('../../utils/errors')
|
||||
const { EXIT_CODES, MAX_CONCURRENT_EVENTS } = require('../../utils/constants')
|
||||
|
||||
const { VALIDATOR_ADDRESS_PRIVATE_KEY } = process.env
|
||||
|
||||
const limit = promiseLimit(MAX_CONCURRENT_EVENTS)
|
||||
|
||||
let validatorContract = null
|
||||
|
||||
function processSignatureRequestsBuilder(config) {
|
||||
const homeBridge = new web3Home.eth.Contract(config.homeBridgeAbi, config.homeBridgeAddress)
|
||||
|
||||
return async function processSignatureRequests(signatureRequests) {
|
||||
const txToSend = []
|
||||
|
||||
if (validatorContract === null) {
|
||||
rootLogger.debug('Getting validator contract address')
|
||||
const validatorContractAddress = await homeBridge.methods.validatorContract().call()
|
||||
rootLogger.debug({ validatorContractAddress }, 'Validator contract address obtained')
|
||||
|
||||
validatorContract = new web3Home.eth.Contract(bridgeValidatorsABI, validatorContractAddress)
|
||||
}
|
||||
|
||||
rootLogger.debug(`Processing ${signatureRequests.length} SignatureRequest events`)
|
||||
const callbacks = signatureRequests.map(signatureRequest =>
|
||||
limit(async () => {
|
||||
const { encodedData } = signatureRequest.returnValues
|
||||
|
||||
const logger = rootLogger.child({
|
||||
eventTransactionHash: signatureRequest.transactionHash
|
||||
})
|
||||
|
||||
const message = addTxHashToData({
|
||||
encodedData,
|
||||
transactionHash: signatureRequest.transactionHash
|
||||
})
|
||||
|
||||
const { sender, executor } = parseAMBMessage(message)
|
||||
logger.info(
|
||||
{ sender, executor },
|
||||
`Processing signatureRequest ${signatureRequest.transactionHash}`
|
||||
)
|
||||
|
||||
const signature = web3Home.eth.accounts.sign(message, `0x${VALIDATOR_ADDRESS_PRIVATE_KEY}`)
|
||||
|
||||
let gasEstimate
|
||||
try {
|
||||
logger.debug('Estimate gas')
|
||||
gasEstimate = await estimateGas({
|
||||
web3: web3Home,
|
||||
homeBridge,
|
||||
validatorContract,
|
||||
signature: signature.signature,
|
||||
message,
|
||||
address: config.validatorAddress
|
||||
})
|
||||
logger.debug({ gasEstimate }, 'Gas estimated')
|
||||
} catch (e) {
|
||||
if (e instanceof HttpListProviderError) {
|
||||
throw new Error(
|
||||
'RPC Connection Error: submitSignature Gas Estimate cannot be obtained.'
|
||||
)
|
||||
} else if (e instanceof InvalidValidatorError) {
|
||||
logger.fatal({ address: config.validatorAddress }, 'Invalid validator')
|
||||
process.exit(EXIT_CODES.INCOMPATIBILITY)
|
||||
} else if (e instanceof AlreadySignedError) {
|
||||
logger.info(`Already signed signatureRequest ${signatureRequest.transactionHash}`)
|
||||
return
|
||||
} else if (e instanceof AlreadyProcessedError) {
|
||||
logger.info(
|
||||
`signatureRequest ${
|
||||
signatureRequest.transactionHash
|
||||
} was already processed by other validators`
|
||||
)
|
||||
return
|
||||
} else {
|
||||
logger.error(e, 'Unknown error while processing transaction')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const data = await homeBridge.methods
|
||||
.submitSignature(signature.signature, message)
|
||||
.encodeABI({ from: config.validatorAddress })
|
||||
|
||||
txToSend.push({
|
||||
data,
|
||||
gasEstimate,
|
||||
transactionReference: signatureRequest.transactionHash,
|
||||
to: config.homeBridgeAddress
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
await Promise.all(callbacks)
|
||||
return txToSend
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = processSignatureRequestsBuilder
|
@ -99,7 +99,6 @@ async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) {
|
||||
|
||||
const txArray = JSON.parse(msg.content)
|
||||
logger.info(`Msg received with ${txArray.length} Tx to send`)
|
||||
const gasPrice = GasPrice.getPrice()
|
||||
|
||||
const ttl = REDIS_LOCK_TTL * txArray.length
|
||||
|
||||
@ -114,6 +113,7 @@ async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) {
|
||||
logger.debug(`Sending ${txArray.length} transactions`)
|
||||
await syncForEach(txArray, async job => {
|
||||
const gasLimit = addExtraGas(job.gasEstimate, EXTRA_GAS_PERCENTAGE)
|
||||
const gasPrice = GasPrice.getPrice(job.gasPriceOptions)
|
||||
|
||||
try {
|
||||
logger.info(`Sending transaction with nonce ${nonce}`)
|
||||
@ -121,7 +121,7 @@ async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) {
|
||||
chain: config.id,
|
||||
data: job.data,
|
||||
nonce,
|
||||
gasPrice: gasPrice.toString(10),
|
||||
gasPrice,
|
||||
amount: '0',
|
||||
gasLimit,
|
||||
privateKey: VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||
|
@ -7,7 +7,11 @@ const logger = require('../services/logger').child({
|
||||
module: 'gasPrice'
|
||||
})
|
||||
const { setIntervalAndRun } = require('../utils/utils')
|
||||
const { DEFAULT_UPDATE_INTERVAL, GAS_PRICE_BOUNDARIES } = require('../utils/constants')
|
||||
const {
|
||||
DEFAULT_UPDATE_INTERVAL,
|
||||
GAS_PRICE_BOUNDARIES,
|
||||
GAS_PRICE_OPTIONS
|
||||
} = require('../utils/constants')
|
||||
|
||||
const HomeABI = bridgeConfig.homeBridgeAbi
|
||||
const ForeignABI = bridgeConfig.foreignBridgeAbi
|
||||
@ -30,6 +34,7 @@ const homeBridge = new web3Home.eth.Contract(HomeABI, HOME_BRIDGE_ADDRESS)
|
||||
const foreignBridge = new web3Foreign.eth.Contract(ForeignABI, FOREIGN_BRIDGE_ADDRESS)
|
||||
|
||||
let cachedGasPrice = null
|
||||
let cachedGasPriceOracleSpeeds = null
|
||||
|
||||
function gasPriceWithinLimits(gasPrice) {
|
||||
if (gasPrice < GAS_PRICE_BOUNDARIES.MIN) {
|
||||
@ -49,13 +54,19 @@ async function fetchGasPriceFromOracle(oracleUrl, speedType) {
|
||||
throw new Error(`Response from Oracle didn't include gas price for ${speedType} type.`)
|
||||
}
|
||||
const gasPrice = gasPriceWithinLimits(oracleGasPrice)
|
||||
return Web3Utils.toWei(gasPrice.toString(), 'gwei')
|
||||
return {
|
||||
oracleGasPrice: Web3Utils.toWei(gasPrice.toString(), 'gwei'),
|
||||
oracleResponse: json
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchGasPrice({ bridgeContract, oracleFn }) {
|
||||
let gasPrice = null
|
||||
let oracleGasPriceSpeeds = null
|
||||
try {
|
||||
gasPrice = await oracleFn()
|
||||
const { oracleGasPrice, oracleResponse } = await oracleFn()
|
||||
gasPrice = oracleGasPrice
|
||||
oracleGasPriceSpeeds = oracleResponse
|
||||
logger.debug({ gasPrice }, 'Gas price updated using the oracle')
|
||||
} catch (e) {
|
||||
logger.error(`Gas Price API is not available. ${e.message}`)
|
||||
@ -67,7 +78,10 @@ async function fetchGasPrice({ bridgeContract, oracleFn }) {
|
||||
logger.error(`There was a problem getting the gas price from the contract. ${e.message}`)
|
||||
}
|
||||
}
|
||||
return gasPrice
|
||||
return {
|
||||
gasPrice,
|
||||
oracleGasPriceSpeeds
|
||||
}
|
||||
}
|
||||
|
||||
let fetchGasPriceInterval = null
|
||||
@ -98,21 +112,36 @@ async function start(chainId) {
|
||||
}
|
||||
|
||||
fetchGasPriceInterval = setIntervalAndRun(async () => {
|
||||
const gasPrice = await fetchGasPrice({
|
||||
const { gasPrice, oracleGasPriceSpeeds } = await fetchGasPrice({
|
||||
bridgeContract,
|
||||
oracleFn: () => fetchGasPriceFromOracle(oracleUrl, speedType)
|
||||
})
|
||||
cachedGasPrice = gasPrice || cachedGasPrice
|
||||
cachedGasPriceOracleSpeeds = oracleGasPriceSpeeds || cachedGasPriceOracleSpeeds
|
||||
}, updateInterval)
|
||||
}
|
||||
|
||||
function getPrice() {
|
||||
return cachedGasPrice
|
||||
function getPrice(options) {
|
||||
return processGasPriceOptions({ options, cachedGasPrice, cachedGasPriceOracleSpeeds })
|
||||
}
|
||||
|
||||
function processGasPriceOptions({ options, cachedGasPrice, cachedGasPriceOracleSpeeds }) {
|
||||
let gasPrice = cachedGasPrice
|
||||
if (options && options.type && options.value) {
|
||||
if (options.type === GAS_PRICE_OPTIONS.GAS_PRICE) {
|
||||
return options.value
|
||||
} else if (options.type === GAS_PRICE_OPTIONS.SPEED) {
|
||||
const speedOption = cachedGasPriceOracleSpeeds[options.value]
|
||||
gasPrice = speedOption ? Web3Utils.toWei(speedOption.toString(), 'gwei') : cachedGasPrice
|
||||
}
|
||||
}
|
||||
return gasPrice
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
start,
|
||||
fetchGasPrice,
|
||||
getPrice,
|
||||
processGasPriceOptions,
|
||||
gasPriceWithinLimits
|
||||
}
|
||||
|
@ -20,5 +20,16 @@ module.exports = {
|
||||
ERC_TYPES: {
|
||||
ERC20: 'ERC20',
|
||||
ERC677: 'ERC677'
|
||||
},
|
||||
GAS_PRICE_OPTIONS: {
|
||||
UNDEFINED: '00',
|
||||
GAS_PRICE: '01',
|
||||
SPEED: '02'
|
||||
},
|
||||
ORACLE_GAS_PRICE_SPEEDS: {
|
||||
SLOW: 'slow',
|
||||
STANDARD: 'standard',
|
||||
FAST: 'fast',
|
||||
INSTANT: 'instant'
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
const assert = require('assert')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const { ORACLE_GAS_PRICE_SPEEDS, GAS_PRICE_OPTIONS } = require('./constants')
|
||||
|
||||
const gasPriceSpeedMapper = {
|
||||
'01': ORACLE_GAS_PRICE_SPEEDS.INSTANT,
|
||||
'02': ORACLE_GAS_PRICE_SPEEDS.FAST,
|
||||
'03': ORACLE_GAS_PRICE_SPEEDS.STANDARD,
|
||||
'04': ORACLE_GAS_PRICE_SPEEDS.SLOW
|
||||
}
|
||||
// strips leading "0x" if present
|
||||
function strip0x(input) {
|
||||
return input.replace(/^0x/, '')
|
||||
@ -72,8 +79,55 @@ function signatureToVRS(signature) {
|
||||
return { v, r, s }
|
||||
}
|
||||
|
||||
function addTxHashToData({ encodedData, transactionHash }) {
|
||||
return encodedData.slice(0, 82) + strip0x(transactionHash) + encodedData.slice(82)
|
||||
}
|
||||
|
||||
function parseAMBMessage(message) {
|
||||
message = strip0x(message)
|
||||
|
||||
const sender = `0x${message.slice(0, 40)}`
|
||||
const executor = `0x${message.slice(40, 80)}`
|
||||
const txHash = `0x${message.slice(80, 144)}`
|
||||
const gasLimit = Web3Utils.toBN(message.slice(144, 208))
|
||||
const dataType = message.slice(208, 210)
|
||||
let gasPrice = null
|
||||
let gasPriceSpeed = null
|
||||
let dataStart = 210
|
||||
|
||||
switch (dataType) {
|
||||
case GAS_PRICE_OPTIONS.GAS_PRICE:
|
||||
gasPrice = Web3Utils.toBN(message.slice(210, 274))
|
||||
dataStart += 64
|
||||
break
|
||||
case GAS_PRICE_OPTIONS.SPEED:
|
||||
gasPriceSpeed = gasPriceSpeedMapper[message.slice(210, 212)]
|
||||
dataStart += 2
|
||||
break
|
||||
case GAS_PRICE_OPTIONS.UNDEFINED:
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
const data = `0x${message.slice(dataStart, message.length)}`
|
||||
|
||||
return {
|
||||
sender,
|
||||
executor,
|
||||
txHash,
|
||||
gasLimit,
|
||||
dataType,
|
||||
gasPrice,
|
||||
gasPriceSpeed,
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createMessage,
|
||||
parseMessage,
|
||||
signatureToVRS
|
||||
signatureToVRS,
|
||||
addTxHashToData,
|
||||
parseAMBMessage,
|
||||
strip0x
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
const BigNumber = require('bignumber.js')
|
||||
const promiseRetry = require('promise-retry')
|
||||
const Web3 = require('web3')
|
||||
const { GAS_PRICE_OPTIONS } = require('./constants')
|
||||
|
||||
async function syncForEach(array, callback) {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
@ -96,6 +97,22 @@ function privateKeyToAddress(privateKey) {
|
||||
: null
|
||||
}
|
||||
|
||||
function generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed }) {
|
||||
let gasPriceOptions = null
|
||||
if (dataType === GAS_PRICE_OPTIONS.GAS_PRICE) {
|
||||
gasPriceOptions = {
|
||||
type: dataType,
|
||||
value: gasPrice
|
||||
}
|
||||
} else if (dataType === GAS_PRICE_OPTIONS.SPEED) {
|
||||
gasPriceOptions = {
|
||||
type: dataType,
|
||||
value: gasPriceSpeed
|
||||
}
|
||||
}
|
||||
return gasPriceOptions
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
syncForEach,
|
||||
checkHTTPS,
|
||||
@ -103,5 +120,6 @@ module.exports = {
|
||||
addExtraGas,
|
||||
setIntervalAndRun,
|
||||
watchdog,
|
||||
privateKeyToAddress
|
||||
privateKeyToAddress,
|
||||
generateGasPriceOptions
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ const processSignatureRequests = require('./events/processSignatureRequests')(co
|
||||
const processCollectedSignatures = require('./events/processCollectedSignatures')(config)
|
||||
const processAffirmationRequests = require('./events/processAffirmationRequests')(config)
|
||||
const processTransfers = require('./events/processTransfers')(config)
|
||||
const processAMBSignatureRequests = require('./events/processAMBSignatureRequests')(config)
|
||||
const processAMBCollectedSignatures = require('./events/processAMBCollectedSignatures')(config)
|
||||
const processAMBAffirmationRequests = require('./events/processAMBAffirmationRequests')(config)
|
||||
|
||||
const ZERO = toBN(0)
|
||||
const ONE = toBN(1)
|
||||
@ -100,6 +103,12 @@ function processEvents(events) {
|
||||
case 'erc-erc-affirmation-request':
|
||||
case 'erc-native-affirmation-request':
|
||||
return processTransfers(events)
|
||||
case 'amb-signature-request':
|
||||
return processAMBSignatureRequests(events)
|
||||
case 'amb-collected-signatures':
|
||||
return processAMBCollectedSignatures(events)
|
||||
case 'amb-affirmation-request':
|
||||
return processAMBAffirmationRequests(events)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
|
@ -1,11 +1,30 @@
|
||||
const sinon = require('sinon')
|
||||
const { expect } = require('chai')
|
||||
const proxyquire = require('proxyquire').noPreserveCache()
|
||||
const { fetchGasPrice, gasPriceWithinLimits } = require('../src/services/gasPrice')
|
||||
const { DEFAULT_UPDATE_INTERVAL, GAS_PRICE_BOUNDARIES } = require('../src/utils/constants')
|
||||
const Web3Utils = require('web3-utils')
|
||||
const {
|
||||
fetchGasPrice,
|
||||
processGasPriceOptions,
|
||||
gasPriceWithinLimits
|
||||
} = require('../src/services/gasPrice')
|
||||
const {
|
||||
DEFAULT_UPDATE_INTERVAL,
|
||||
GAS_PRICE_OPTIONS,
|
||||
ORACLE_GAS_PRICE_SPEEDS,
|
||||
GAS_PRICE_BOUNDARIES
|
||||
} = require('../src/utils/constants')
|
||||
|
||||
describe('gasPrice', () => {
|
||||
describe('fetchGasPrice', () => {
|
||||
const oracleMockResponse = {
|
||||
fast: 17.64,
|
||||
block_time: 13.548,
|
||||
health: true,
|
||||
standard: 10.64,
|
||||
block_number: 6704240,
|
||||
instant: 51.9,
|
||||
slow: 4.4
|
||||
}
|
||||
beforeEach(() => {
|
||||
sinon.stub(console, 'error')
|
||||
})
|
||||
@ -15,7 +34,11 @@ describe('gasPrice', () => {
|
||||
|
||||
it('should fetch the gas price from the oracle by default', async () => {
|
||||
// given
|
||||
const oracleFnMock = () => Promise.resolve('1')
|
||||
const oracleFnMock = () =>
|
||||
Promise.resolve({
|
||||
oracleGasPrice: '1',
|
||||
oracleResponse: oracleMockResponse
|
||||
})
|
||||
const bridgeContractMock = {
|
||||
methods: {
|
||||
gasPrice: {
|
||||
@ -25,13 +48,14 @@ describe('gasPrice', () => {
|
||||
}
|
||||
|
||||
// when
|
||||
const gasPrice = await fetchGasPrice({
|
||||
const { gasPrice, oracleGasPriceSpeeds } = await fetchGasPrice({
|
||||
bridgeContract: bridgeContractMock,
|
||||
oracleFn: oracleFnMock
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal('1')
|
||||
expect(oracleGasPriceSpeeds).to.equal(oracleMockResponse)
|
||||
})
|
||||
it('should fetch the gas price from the contract if the oracle fails', async () => {
|
||||
// given
|
||||
@ -45,13 +69,14 @@ describe('gasPrice', () => {
|
||||
}
|
||||
|
||||
// when
|
||||
const gasPrice = await fetchGasPrice({
|
||||
const { gasPrice, oracleGasPriceSpeeds } = await fetchGasPrice({
|
||||
bridgeContract: bridgeContractMock,
|
||||
oracleFn: oracleFnMock
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal('2')
|
||||
expect(oracleGasPriceSpeeds).to.equal(null)
|
||||
})
|
||||
it('should return null if both the oracle and the contract fail', async () => {
|
||||
// given
|
||||
@ -65,13 +90,14 @@ describe('gasPrice', () => {
|
||||
}
|
||||
|
||||
// when
|
||||
const gasPrice = await fetchGasPrice({
|
||||
const { gasPrice, oracleGasPriceSpeeds } = await fetchGasPrice({
|
||||
bridgeContract: bridgeContractMock,
|
||||
oracleFn: oracleFnMock
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal(null)
|
||||
expect(oracleGasPriceSpeeds).to.equal(null)
|
||||
})
|
||||
})
|
||||
describe('start', () => {
|
||||
@ -176,4 +202,86 @@ describe('gasPrice', () => {
|
||||
expect(gasPrice).to.equal(GAS_PRICE_BOUNDARIES.MAX)
|
||||
})
|
||||
})
|
||||
describe('processGasPriceOptions', () => {
|
||||
const oracleMockResponse = {
|
||||
fast: 17.64,
|
||||
block_time: 13.548,
|
||||
health: true,
|
||||
standard: 10.64,
|
||||
block_number: 6704240,
|
||||
instant: 51.9,
|
||||
slow: 4.4
|
||||
}
|
||||
it('should return cached gas price if no options provided', async () => {
|
||||
// given
|
||||
const options = {}
|
||||
const cachedGasPrice = '1000000000'
|
||||
|
||||
// when
|
||||
const gasPrice = await processGasPriceOptions({
|
||||
options,
|
||||
cachedGasPrice,
|
||||
cachedGasPriceOracleSpeeds: oracleMockResponse
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal(cachedGasPrice)
|
||||
})
|
||||
it('should return gas price provided by options', async () => {
|
||||
// given
|
||||
const options = {
|
||||
type: GAS_PRICE_OPTIONS.GAS_PRICE,
|
||||
value: '3000000000'
|
||||
}
|
||||
const cachedGasPrice = '1000000000'
|
||||
|
||||
// when
|
||||
const gasPrice = await processGasPriceOptions({
|
||||
options,
|
||||
cachedGasPrice,
|
||||
cachedGasPriceOracleSpeeds: oracleMockResponse
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal(options.value)
|
||||
})
|
||||
it('should return gas price provided by oracle speed option', async () => {
|
||||
// given
|
||||
const options = {
|
||||
type: GAS_PRICE_OPTIONS.SPEED,
|
||||
value: ORACLE_GAS_PRICE_SPEEDS.STANDARD
|
||||
}
|
||||
const cachedGasPrice = '1000000000'
|
||||
const oracleGasPriceGwei = oracleMockResponse[ORACLE_GAS_PRICE_SPEEDS.STANDARD]
|
||||
const oracleGasPrice = Web3Utils.toWei(oracleGasPriceGwei.toString(), 'gwei')
|
||||
|
||||
// when
|
||||
const gasPrice = await processGasPriceOptions({
|
||||
options,
|
||||
cachedGasPrice,
|
||||
cachedGasPriceOracleSpeeds: oracleMockResponse
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal(oracleGasPrice)
|
||||
})
|
||||
it('should return cached gas price if invalid speed option', async () => {
|
||||
// given
|
||||
const options = {
|
||||
type: GAS_PRICE_OPTIONS.SPEED,
|
||||
value: 'unknown'
|
||||
}
|
||||
const cachedGasPrice = '1000000000'
|
||||
|
||||
// when
|
||||
const gasPrice = await processGasPriceOptions({
|
||||
options,
|
||||
cachedGasPrice,
|
||||
cachedGasPriceOracleSpeeds: oracleMockResponse
|
||||
})
|
||||
|
||||
// then
|
||||
expect(gasPrice).to.equal(cachedGasPrice)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,13 @@
|
||||
const { BN, toBN } = require('web3').utils
|
||||
const { expect } = require('chai').use(require('bn-chai')(BN))
|
||||
const { createMessage, parseMessage, signatureToVRS } = require('../src/utils/message')
|
||||
const {
|
||||
createMessage,
|
||||
parseMessage,
|
||||
signatureToVRS,
|
||||
parseAMBMessage,
|
||||
strip0x
|
||||
} = require('../src/utils/message')
|
||||
const { ORACLE_GAS_PRICE_SPEEDS } = require('../src/utils/constants')
|
||||
|
||||
describe('message utils', () => {
|
||||
const expectedMessageLength = 104
|
||||
@ -293,4 +300,107 @@ describe('message utils', () => {
|
||||
expect(signatureThunk).to.throw()
|
||||
})
|
||||
})
|
||||
describe('parseAMBMessage', () => {
|
||||
it('should parse data type 00', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgSender)}${strip0x(msgExecutor)}${strip0x(
|
||||
msgTxHash
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const {
|
||||
sender,
|
||||
executor,
|
||||
txHash,
|
||||
gasLimit,
|
||||
dataType,
|
||||
gasPrice,
|
||||
gasPriceSpeed,
|
||||
data
|
||||
} = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.be.equal(null)
|
||||
expect(gasPriceSpeed).to.be.equal(null)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
it('should parse data type 01', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '01'
|
||||
const msgGasPrice = '0000000000000000000000000000000000000000000000000000000165a0bc00'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgSender)}${strip0x(msgExecutor)}${strip0x(
|
||||
msgTxHash
|
||||
)}${msgGasLimit}${msgDataType}${msgGasPrice}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const {
|
||||
sender,
|
||||
executor,
|
||||
txHash,
|
||||
gasLimit,
|
||||
dataType,
|
||||
gasPrice,
|
||||
gasPriceSpeed,
|
||||
data
|
||||
} = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.eq.BN(toBN(msgGasPrice))
|
||||
expect(gasPriceSpeed).to.be.equal(null)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
it('should parse data type 02', () => {
|
||||
const msgSender = '0x003667154bb32e42bb9e1e6532f19d187fa0082e'
|
||||
const msgExecutor = '0xf4bef13f9f4f2b203faf0c3cbbaabe1afe056955'
|
||||
const msgTxHash = '0xbdceda9d8c94838aca10c687da1411a07b1390e88239c0638cb9cc264219cc10'
|
||||
const msgGasLimit = '000000000000000000000000000000000000000000000000000000005b877705'
|
||||
const msgDataType = '02'
|
||||
const msgGasPriceSpeed = '0x03'
|
||||
const msgData = '0xb1591967aed668a4b27645ff40c444892d91bf5951b382995d4d4f6ee3a2ce03'
|
||||
const message = `0x${strip0x(msgSender)}${strip0x(msgExecutor)}${strip0x(
|
||||
msgTxHash
|
||||
)}${msgGasLimit}${msgDataType}${strip0x(msgGasPriceSpeed)}${strip0x(msgData)}`
|
||||
|
||||
// when
|
||||
const {
|
||||
sender,
|
||||
executor,
|
||||
txHash,
|
||||
gasLimit,
|
||||
dataType,
|
||||
gasPrice,
|
||||
gasPriceSpeed,
|
||||
data
|
||||
} = parseAMBMessage(message)
|
||||
|
||||
// then
|
||||
expect(sender).to.be.equal(msgSender)
|
||||
expect(executor).to.be.equal(msgExecutor)
|
||||
expect(txHash).to.be.equal(msgTxHash)
|
||||
expect(gasLimit).to.eq.BN(toBN(msgGasLimit))
|
||||
expect(dataType).to.be.equal(msgDataType)
|
||||
expect(gasPrice).to.be.equal(null)
|
||||
expect(gasPriceSpeed).to.be.equal(ORACLE_GAS_PRICE_SPEEDS.STANDARD)
|
||||
expect(data).to.be.equal(msgData)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -3,7 +3,8 @@ const chai = require('chai')
|
||||
const chaiAsPromised = require('chai-as-promised')
|
||||
const BigNumber = require('bignumber.js')
|
||||
const proxyquire = require('proxyquire')
|
||||
const { addExtraGas, syncForEach } = require('../src/utils/utils')
|
||||
const { addExtraGas, syncForEach, generateGasPriceOptions } = require('../src/utils/utils')
|
||||
const { GAS_PRICE_OPTIONS, ORACLE_GAS_PRICE_SPEEDS } = require('../src/utils/constants')
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
const { expect } = chai
|
||||
@ -134,4 +135,54 @@ describe('utils', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('generateGasPriceOptions', () => {
|
||||
it('should work for GAS_PRICE option', () => {
|
||||
// given
|
||||
const dataType = GAS_PRICE_OPTIONS.GAS_PRICE
|
||||
const gasPrice = BigNumber('0000000000000000000000000000000000000000000000000000000165a0bc00')
|
||||
const gasPriceSpeed = null
|
||||
|
||||
const expectedResult = {
|
||||
type: dataType,
|
||||
value: gasPrice
|
||||
}
|
||||
|
||||
// when
|
||||
const gasPriceOptions = generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed })
|
||||
|
||||
// then
|
||||
expect(gasPriceOptions.type).to.be.equal(expectedResult.type)
|
||||
expect(gasPriceOptions.value).to.be.equal(expectedResult.value)
|
||||
})
|
||||
it('should work for SPEED option', () => {
|
||||
// given
|
||||
const dataType = GAS_PRICE_OPTIONS.SPEED
|
||||
const gasPrice = null
|
||||
const gasPriceSpeed = ORACLE_GAS_PRICE_SPEEDS.STANDARD
|
||||
|
||||
const expectedResult = {
|
||||
type: dataType,
|
||||
value: gasPriceSpeed
|
||||
}
|
||||
|
||||
// when
|
||||
const gasPriceOptions = generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed })
|
||||
|
||||
// then
|
||||
expect(gasPriceOptions.type).to.be.equal(expectedResult.type)
|
||||
expect(gasPriceOptions.value).to.be.equal(expectedResult.value)
|
||||
})
|
||||
it('should return null option for undefined option', () => {
|
||||
// given
|
||||
const dataType = GAS_PRICE_OPTIONS.UNDEFINED
|
||||
const gasPrice = null
|
||||
const gasPriceSpeed = null
|
||||
|
||||
// when
|
||||
const gasPriceOptions = generateGasPriceOptions({ dataType, gasPrice, gasPriceSpeed })
|
||||
|
||||
// then
|
||||
expect(gasPriceOptions).to.be.equal(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user