diff --git a/contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol b/contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol index 6a8b11d05..a4dfffbe1 100644 --- a/contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol +++ b/contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol @@ -12,6 +12,10 @@ contract BasicAMB is BasicBridge, VersionableAMB { bytes32 internal constant DESTINATION_CHAIN_ID_LENGTH = 0xfb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d4989692811594; // keccak256(abi.encodePacked("destinationChainIdLength")) bytes32 internal constant ALLOW_REENTRANT_REQUESTS = 0xffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd6; // keccak256(abi.encodePacked("allowReentrantRequests")) + bytes32 internal constant TELEPATHY_SOURCE_AMB = bytes32(0); + bytes32 internal constant TELEPATHY_AGENT = bytes32(1); + bytes32 internal constant OTHERSIDE_TELEPATHY_AGENT = bytes32(2); + /** * Initializes AMB contract * @param _sourceChainId chain id of a network where this contract is deployed @@ -191,4 +195,28 @@ contract BasicAMB is BasicBridge, VersionableAMB { function _isDestinationChainIdValid(uint256 _chainId) internal returns (bool res) { return _chainId == sourceChainId(); } + + function setTelepathySourceAMB(address addr) external onlyOwner { + addressStorage[TELEPATHY_SOURCE_AMB] = addr; + } + + function getTelepathySourceAMB() public view returns (address) { + return addressStorage[TELEPATHY_SOURCE_AMB]; + } + + function setTelepathyAgent(address addr) external onlyOwner { + addressStorage[TELEPATHY_AGENT] = addr; + } + + function getTelepathyAgent() public view returns (address) { + return addressStorage[TELEPATHY_AGENT]; + } + + function setOthersideTelepathyAgent(address addr) external onlyOwner { + addressStorage[OTHERSIDE_TELEPATHY_AGENT] = addr; + } + + function getOthersideTelepathyAgent() public view returns (address) { + return addressStorage[OTHERSIDE_TELEPATHY_AGENT]; + } } diff --git a/contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol b/contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol index 08914573a..40162d800 100644 --- a/contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol +++ b/contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol @@ -5,6 +5,7 @@ import "../../libraries/ArbitraryMessage.sol"; import "./BasicAMB.sol"; import "./MessageDelivery.sol"; import "../MessageRelay.sol"; +import "../telepathy/Interfaces.sol"; contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery { /** @@ -25,6 +26,10 @@ contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery { (msgId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_data); + address telepathyAgent = getTelepathyAgent(); + bytes32 messageId = keccak256(_data); + require(ITelepathyForeignApprover(telepathyAgent).isApproved(messageId)); + _executeMessage(msgId, sender, executor, gasLimit, dataType, chainIds, data); } diff --git a/contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol b/contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol index 1bff1d607..74ec66565 100644 --- a/contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol +++ b/contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol @@ -5,6 +5,8 @@ import "./BasicAMB.sol"; import "./MessageProcessor.sol"; import "../../libraries/ArbitraryMessage.sol"; import "../../libraries/Bytes.sol"; +import "../telepathy/Interfaces.sol"; + contract MessageDelivery is BasicAMB, MessageProcessor { using SafeMath for uint256; @@ -62,6 +64,11 @@ contract MessageDelivery is BasicAMB, MessageProcessor { bytes memory eventData = abi.encodePacked(header, _data); + uint16 destChainId = uint16(destinationChainId()); + address telepathySourceAMB = getTelepathySourceAMB(); + address othersideTelepathyAgent = getOthersideTelepathyAgent(); + ISourceAMB(telepathySourceAMB).send(othersideTelepathyAgent, destChainId, _gas, eventData); + emitEventOnMessageRequest(_messageId, eventData); return _messageId; } diff --git a/contracts/upgradeable_contracts/telepathy/ForeignApprover.sol b/contracts/upgradeable_contracts/telepathy/ForeignApprover.sol new file mode 100644 index 000000000..64e557360 --- /dev/null +++ b/contracts/upgradeable_contracts/telepathy/ForeignApprover.sol @@ -0,0 +1,27 @@ +pragma solidity 0.4.24; + +contract TelepathyForeignApprover { + bool public initialized = false; + address public foreignTelepathyReceiver; + address public homeOmnibridgeAMB; + mapping(bytes32 => bool) public approvals; + + function initialize(address _foreignTelepathyReceiver, address _homeOmnibridgeAMB) external { + require(!initialized); + foreignTelepathyReceiver = _foreignTelepathyReceiver; + homeOmnibridgeAMB = _homeOmnibridgeAMB; + initialized = true; + } + + function isApproved(bytes32 messageId) public view returns (bool) { + return approvals[messageId]; + } + + function receiveSuccinct(address srcAddress, bytes message) external { + require(msg.sender == foreignTelepathyReceiver); + require(srcAddress == homeOmnibridgeAMB); + bytes32 messageId = keccak256(message); + approvals[messageId] = true; + } +} +} \ No newline at end of file diff --git a/contracts/upgradeable_contracts/telepathy/HomeValidator.sol b/contracts/upgradeable_contracts/telepathy/HomeValidator.sol new file mode 100644 index 000000000..fadd891df --- /dev/null +++ b/contracts/upgradeable_contracts/telepathy/HomeValidator.sol @@ -0,0 +1,24 @@ +pragma solidity 0.4.24; + +import "./Interfaces.sol"; + +contract TelepathyHomeValidator { + bool public initialized = false; + address public homeTelepathyReceiver; + address public homeOmnibridgeAMB; + address public foreignOmnibridgeAMB; + + function initialize(address _homeTelepathyReceiver, address _homeOmnibridgeAMB, address _foreignOmnibridgeAMB) { + require(!initialized); + homeTelepathyReceiver = _homeTelepathyReceiver; + homeOmnibridgeAMB = _homeOmnibridgeAMB; + foreignOmnibridgeAMB = _foreignOmnibridgeAMB; + initialized = true; + } + + function receiveSuccinct(address srcAddress, bytes message) external { + require(msg.sender == homeTelepathyReceiver); + require(srcAddress == foreignOmnibridgeAMB); + IHomeOmnibridgeAMB(homeOmnibridgeAMB).executeAffirmation(message); + } +} \ No newline at end of file diff --git a/contracts/upgradeable_contracts/telepathy/Interfaces.sol b/contracts/upgradeable_contracts/telepathy/Interfaces.sol new file mode 100644 index 000000000..b742f0b0e --- /dev/null +++ b/contracts/upgradeable_contracts/telepathy/Interfaces.sol @@ -0,0 +1,11 @@ +interface ISourceAMB { + function send(address receiver, uint16 chainId, uint256 gasLimit, bytes data) external returns (bytes32); +} + +interface ITelepathyForeignApprover { + function isApproved(bytes32 messageId) external returns (bool); +} + +interface IHomeOmnibridgeAMB { + function executeAffirmation(bytes message) external; +} \ No newline at end of file diff --git a/deploy/deploy.js b/deploy/deploy.js index 045beb2a5..65d8c9dcb 100644 --- a/deploy/deploy.js +++ b/deploy/deploy.js @@ -35,6 +35,7 @@ async function deployArbitraryMessage() { const preDeploy = require('./src/arbitrary_message/preDeploy') const deployHome = require('./src/arbitrary_message/home') const deployForeign = require('./src/arbitrary_message/foreign') + await preDeploy() const { homeBridge } = await deployHome() const { foreignBridge } = await deployForeign() diff --git a/deploy/postDeploy.js b/deploy/postDeploy.js new file mode 100644 index 000000000..f8f91b29d --- /dev/null +++ b/deploy/postDeploy.js @@ -0,0 +1,103 @@ +const assert = require('assert') +const Web3Utils = require('web3-utils') + +const env = require('../loadEnv') +const { privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils') +const { web3Home, web3Foreign, deploymentPrivateKey, HOME_RPC_URL, FOREIGN_RPC_URL } = require('../web3') + +const { + homeContracts: { HomeAMB: HomeBridge, ForeignAMB: ForeignBridge } +} = require('../loadContracts') + +const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = env + +const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) + +async function executeTransactions({ bridge, initialNonce, succinctAddress, otherAMBAddress, RPC_URL }) { + let nonce = initialNonce + + const setSuccinctData = await bridge.methods + .setSuccinctAMBAddress(succinctAddress) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + console.log('Setting Succinct Address') + console.log({ + data: setSuccinctData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: RPC_URL + }) + const setSuccinctTx = await sendRawTxHome({ + data: setSuccinctData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: RPC_URL + }) + if (setSuccinctTx.status) { + assert.strictEqual(Web3Utils.hexToNumber(setSuccinctTx.status), 1, 'Transaction Failed') + } else { + console.log('Transaction failed') + // await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + nonce++ + const setOtherAMBData = await bridge.methods + .setOtherSideAMBAddress(otherAMBAddress) + .encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS }) + console.log('Setting other side AMB address') + const setOtherAMBTx = await sendRawTxHome({ + data: setOtherAMBData, + nonce, + to: bridge.options.address, + privateKey: deploymentPrivateKey, + url: RPC_URL + }) + if (setOtherAMBTx.status) { + assert.strictEqual(Web3Utils.hexToNumber(setOtherAMBTx.status), 1, 'Transaction Failed') + } else { + console.log('Transaction failed') + // await assertStateWithRetry(bridge.methods.isInitialized().call, true) + } + return nonce +} + +async function main() { + console.log('============================================') + console.log('Running post-deployment setting of variables') + console.log('============================================\n') + + const SUCCINCT_HOME_SOURCE_AMB_ADDRESS = '0xd667A279A51fE457f934A5c487FC490B91A77d1a'; + const SUCCINCT_HOME_TARGET_AMB_ADDRESS = '0xef604f14B99a37bf88F239C85A8826AeB2D9D699'; + const SUCCINCT_FOREIGN_SOURCE_AMB_ADDRESS = '0x39323dC5A276553EF7fD16Ed3164175747eB254c'; + const SUCCINCT_FOREIGN_TARGET_AMB_ADDRESS = '0xbc394A38fD6a76F254d14886bCe053279eAffB46'; + + const HOME_TOKENBRIDGE_AMB = '0xFc8D4E3C19B42A9a1cb3B79f925e2382555ceE67' + const FOREIGN_TOKENBRIDGE_AMB = '0x058C1b0Cb334fEb31BcAb58e8f967d083eddf1be' + + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + const homeBridge = new web3Home.eth.Contract(HomeBridge.abi, { from: DEPLOYMENT_ACCOUNT_ADDRESS }) + homeBridge.options.address = HOME_TOKENBRIDGE_AMB + + console.log('Setting up addresses for home AMB') + await executeTransactions({ + bridge: homeBridge, + initialNonce: nonce, + succinctAddress: HOME_SUCCINCT_ADDRESS, + otherAMBAddress: FOREIGN_TOKENBRIDGE_AMB, + RPC_URL: HOME_RPC_URL + }) + + let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + const foreignBridge = new web3Foreign.eth.Contract(ForeignBridge.abi, { from: DEPLOYMENT_ACCOUNT_ADDRESS }) + foreignBridge.options.address = FOREIGN_TOKENBRIDGE_AMB + console.log('Setting up addresses for foreign AMB') + await executeTransactions({ + bridge: foreignBridge, + initialNonce: foreignNonce, + succinctAddress: FOREIGN_SUCCINCT_ADDRESS, + otherAMBAddress: HOME_TOKENBRIDGE_AMB, + RPC_URL: FOREIGN_RPC_URL + }) +} + +main() \ No newline at end of file diff --git a/deploy/src/arbitrary_message/approver.js b/deploy/src/arbitrary_message/approver.js new file mode 100644 index 000000000..775df8fec --- /dev/null +++ b/deploy/src/arbitrary_message/approver.js @@ -0,0 +1,25 @@ +const env = require('../loadEnv') +const { + deployContract, + privateKeyToAddress, +} = require('../deploymentUtils') +const { web3Home } = require('../web3') +const { homeContracts: { TelepathyForeignApprover } } = require('../loadContracts') +const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = env + +const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) + +async function deployTelepathyForeignApprover() { + console.log('========================================') + console.log('Deploying Telepathy Foreign Approver') + console.log('========================================\n') + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + const telepathyForeignApprover = await deployContract(TelepathyForeignApprover, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + network: 'foreign', + nonce + }) + console.log('Telepathy Foreign Approver', telepathyForeignApprover.options.address) +} + +module.exports = deployTelepathyForeignApprover \ No newline at end of file diff --git a/deploy/src/arbitrary_message/foreign.js b/deploy/src/arbitrary_message/foreign.js index 91c20312e..b07da0df2 100644 --- a/deploy/src/arbitrary_message/foreign.js +++ b/deploy/src/arbitrary_message/foreign.js @@ -17,11 +17,11 @@ const { foreignContracts: { EternalStorageProxy, BridgeValidators, ForeignAMB: ForeignBridge } } = require('../loadContracts') -const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS = env.FOREIGN_VALIDATORS.split(' ') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, - REQUIRED_NUMBER_OF_VALIDATORS, + FOREIGN_REQUIRED_NUMBER_OF_VALIDATORS, FOREIGN_GAS_PRICE, FOREIGN_BRIDGE_OWNER, FOREIGN_VALIDATORS_OWNER, @@ -30,6 +30,8 @@ const { FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS } = env +const REQUIRED_NUMBER_OF_VALIDATORS = FOREIGN_REQUIRED_NUMBER_OF_VALIDATORS + const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) async function initializeBridge({ validatorsBridge, bridge, initialNonce }) { diff --git a/deploy/src/arbitrary_message/home.js b/deploy/src/arbitrary_message/home.js index 4087765f4..4a9f20fbb 100644 --- a/deploy/src/arbitrary_message/home.js +++ b/deploy/src/arbitrary_message/home.js @@ -17,11 +17,11 @@ const { homeContracts: { EternalStorageProxy, BridgeValidators, HomeAMB: HomeBridge } } = require('../loadContracts') -const VALIDATORS = env.VALIDATORS.split(' ') +const VALIDATORS = env.HOME_VALIDATORS.split(' ') const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY, - REQUIRED_NUMBER_OF_VALIDATORS, + HOME_REQUIRED_NUMBER_OF_VALIDATORS, HOME_GAS_PRICE, HOME_BRIDGE_OWNER, HOME_VALIDATORS_OWNER, @@ -30,6 +30,8 @@ const { HOME_REQUIRED_BLOCK_CONFIRMATIONS } = env +const REQUIRED_NUMBER_OF_VALIDATORS = HOME_REQUIRED_NUMBER_OF_VALIDATORS + const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) async function initializeBridge({ validatorsBridge, bridge, initialNonce }) { diff --git a/deploy/src/arbitrary_message/validator.js b/deploy/src/arbitrary_message/validator.js new file mode 100644 index 000000000..bb3fd9d9d --- /dev/null +++ b/deploy/src/arbitrary_message/validator.js @@ -0,0 +1,25 @@ +const env = require('../loadEnv') +const { + deployContract, + privateKeyToAddress, +} = require('../deploymentUtils') +const { web3Home } = require('../web3') +const { homeContracts: { TelepathyHomeValidator } } = require('../loadContracts') +const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = env + +const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY) + +async function deployTelepathyHomeValidator() { + console.log('========================================') + console.log('Deploying Telepathy Home Validator') + console.log('========================================\n') + let nonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS) + const telepathyForeignApprover = await deployContract(TelepathyHomeValidator, [], { + from: DEPLOYMENT_ACCOUNT_ADDRESS, + network: 'home', + nonce + }) + console.log('Telepathy Home Validator', telepathyForeignApprover.options.address) +} + +module.exports = deployTelepathyHomeValidator \ No newline at end of file diff --git a/deploy/src/loadContracts.js b/deploy/src/loadContracts.js index 509d556d6..f7793aa27 100644 --- a/deploy/src/loadContracts.js +++ b/deploy/src/loadContracts.js @@ -19,7 +19,9 @@ function getContracts() { HomeAMB: require(`../../build/${buildPath}/HomeAMB.json`), ForeignAMB: require(`../../build/${buildPath}/ForeignAMB`), HomeAMBErc677ToErc677: require(`../../build/${buildPath}/HomeAMBErc677ToErc677.json`), - ForeignAMBErc677ToErc677: require(`../../build/${buildPath}/ForeignAMBErc677ToErc677.json`) + ForeignAMBErc677ToErc677: require(`../../build/${buildPath}/ForeignAMBErc677ToErc677.json`), + TelepathyForeignApprover: require(`../../build/${buildPath}/TelepathyForeignApprover.json`), + TelepathyHomeValidator: require(`../../build/${buildPath}/TelepathyHomeValidator.json`) } }