Merge branch 'develop' into fix-interface-version-#92

# Conflicts:
#	contracts/ERC677BridgeToken.sol
#	contracts/upgradeable_contracts/BasicBridge.sol
This commit is contained in:
Gerardo Nardelli 2018-10-19 12:20:17 -03:00
commit 2465bc82f8
33 changed files with 4262 additions and 923 deletions

View File

@ -13,6 +13,7 @@ Please refer to the bridge process documentation to configure and deploy the bri
Currently, the contracts support two types of relay operations:
* Tokenize the native coin in one blockchain network (Home) into an ERC20 token in another network (Foreign).
* Swap a token presented by an existing ERC20 contract in a Foreign network into an ERC20 token in the Home network, where one pair of bridge contracts corresponds to one pair of ERC20 tokens.
* to mint new native coins in Home blockchain network from a token presented by an existing ERC20 contract in a Foreign network.
### Components
@ -23,6 +24,7 @@ The POA bridge contracts consist of several components:
* Depending on the type of relay operations the following components are also used:
* in `NATIVE-TO-ERC` mode: the ERC20 token (in fact, the ERC677 extension is used) is deployed on the Foreign network;
* in `ERC-TO-ERC` mode: the ERC20 token (in fact, the ERC677 extension is used) is deployed on the Home network;
* in `ERC-TO-NATIVE` mode: The home network nodes must support consensus engine that allows using a smart contract for block reward calculation;
* The **Validators** smart contract is deployed in both the POA.Network and the Ethereum Mainnet.
### Bridge Roles and Responsibilities
@ -43,7 +45,8 @@ Responsibilities and roles of the bridge:
- **User** role:
- sends assets to Bridge contracts:
- in `NATIVE-TO-ERC` mode: send native coins to the Home Bridge to receive ERC20 tokens from the Foreign Bridge, send ERC20 tokens to the Foreign Bridge to unlock native coins from the Home Bridge;
- in `ERC-TO-ERC` mode: transfer ERC20 tokens to the Foreign Bridge to mint ERC20 tokens on the Home Network, transfer ERC20 tokens to the Home Bridge to unlock ERC20 tokens on Foreign networks.
- in `ERC-TO-ERC` mode: transfer ERC20 tokens to the Foreign Bridge to mint ERC20 tokens on the Home Network, transfer ERC20 tokens to the Home Bridge to unlock ERC20 tokens on Foreign networks;
- in `ERC-TO-NATIVE` mode: send ERC20 tokens to the Foreign Bridge to receive native coins from the Home Bridge, send native coins to the Home Bridge to unlock ERC20 tokens from the Foreign Bridge.
## Usage

View File

@ -13,12 +13,21 @@ contract ERC677BridgeToken is
BurnableToken,
MintableToken {
address public bridgeContract;
event ContractFallbackCallFailed(address from, address to, uint value);
constructor(
string _name,
string _symbol,
uint8 _decimals)
public DetailedERC20(_name, _symbol, _decimals) {}
function setBridgeContract(address _bridgeContract) onlyOwner public {
require(_bridgeContract != address(0) && isContract(_bridgeContract));
bridgeContract = _bridgeContract;
}
modifier validRecipient(address _recipient) {
require(_recipient != address(0) && _recipient != address(this));
_;
@ -48,8 +57,12 @@ contract ERC677BridgeToken is
function transfer(address _to, uint256 _value) public returns (bool)
{
require(superTransfer(_to, _value));
if (isContract(_to)) {
contractFallback(_to, _value, new bytes(0));
if (isContract(_to) && !contractFallback(_to, _value, new bytes(0))) {
if (_to == bridgeContract) {
revert();
} else {
emit ContractFallbackCallFailed(msg.sender, _to, _value);
}
}
return true;
}

View File

@ -0,0 +1,9 @@
pragma solidity 0.4.24;
interface IBlockReward {
function addExtraReceiver(uint256 _amount, address _receiver) external;
function mintedTotally() public view returns (uint256);
function mintedTotallyByBridge(address _bridge) public view returns(uint256);
function bridgesAllowedLength() external view returns(uint256);
}

View File

@ -0,0 +1,43 @@
pragma solidity 0.4.24;
import "../IBlockReward.sol";
import "../libraries/SafeMath.sol";
contract BlockReward is IBlockReward {
using SafeMath for uint256;
uint256 public mintedCoins = 0;
mapping(bytes32 => uint256) internal uintStorage;
bytes32 internal constant MINTED_TOTALLY_BY_BRIDGE = "mintedTotallyByBridge";
function () external payable {
}
function bridgesAllowedLength() external view returns(uint256) {
return 3;
}
function addExtraReceiver(uint256 _amount, address _receiver) external {
require(_amount > 0);
require(_receiver != address(0));
mintedCoins = mintedCoins.add(_amount);
this.addMintedTotallyByBridge(_amount, msg.sender);
_receiver.transfer(_amount);
}
function mintedTotally() public view returns (uint256) {
return mintedCoins;
}
function mintedTotallyByBridge(address _bridge) public view returns(uint256) {
return uintStorage[
keccak256(abi.encode(MINTED_TOTALLY_BY_BRIDGE, _bridge))
];
}
function addMintedTotallyByBridge(uint256 _amount, address _bridge) external {
bytes32 hash = keccak256(abi.encode(MINTED_TOTALLY_BY_BRIDGE, _bridge));
uintStorage[hash] = uintStorage[hash].add(_amount);
}
}

View File

@ -14,7 +14,7 @@ contract BasicBridge is EternalStorage, Validatable {
event DailyLimitChanged(uint256 newLimit);
function getBridgeInterfacesVersion() public pure returns(uint64 major, uint64 minor, uint64 patch) {
return (2, 0, 0);
return (2, 1, 0);
}
function setGasPrice(uint256 _gasPrice) public onlyOwner {
@ -105,4 +105,11 @@ contract BasicBridge is EternalStorage, Validatable {
require(token.transfer(_to, balance));
}
function isContract(address _addr) internal view returns (bool)
{
uint length;
assembly { length := extcodesize(_addr) }
return length > 0;
}
}

View File

@ -15,15 +15,18 @@ contract ForeignBridgeErcToErc is BasicBridge, BasicForeignBridge {
function initialize(
address _validatorContract,
address _erc20token,
uint256 _requiredBlockConfirmations
uint256 _requiredBlockConfirmations,
uint256 _gasPrice
) public returns(bool) {
require(!isInitialized(), "already initialized");
require(_validatorContract != address(0), "address cannot be empty");
require(_requiredBlockConfirmations != 0, "requiredBlockConfirmations cannot be 0");
require(!isInitialized());
require(_validatorContract != address(0));
require(_requiredBlockConfirmations != 0);
require(_gasPrice > 0);
addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract;
setErc20token(_erc20token);
uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number;
uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations;
uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _gasPrice;
setInitialize(true);
return isInitialized();
}

View File

@ -0,0 +1,54 @@
pragma solidity 0.4.24;
import "../../libraries/SafeMath.sol";
import "../../libraries/Message.sol";
import "../BasicBridge.sol";
import "../BasicForeignBridge.sol";
import "../../IBurnableMintableERC677Token.sol";
import "../../ERC677Receiver.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol";
contract ForeignBridgeErcToNative is BasicBridge, BasicForeignBridge {
event RelayedMessage(address recipient, uint value, bytes32 transactionHash);
function initialize(
address _validatorContract,
address _erc20token,
uint256 _requiredBlockConfirmations,
uint256 _gasPrice
) public returns(bool) {
require(!isInitialized());
require(_validatorContract != address(0));
require(_requiredBlockConfirmations != 0);
require(_gasPrice > 0);
addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract;
setErc20token(_erc20token);
uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number;
uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations;
uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _gasPrice;
setInitialize(true);
return isInitialized();
}
function getBridgeMode() public pure returns(bytes4 _data) {
return bytes4(keccak256(abi.encodePacked("erc-to-native-core")));
}
function claimTokens(address _token, address _to) public onlyOwner {
require(_token != address(erc20token()));
super.claimTokens(_token, _to);
}
function erc20token() public view returns(ERC20Basic) {
return ERC20Basic(addressStorage[keccak256(abi.encodePacked("erc20token"))]);
}
function onExecuteMessage(address _recipient, uint256 _amount) internal returns(bool) {
return erc20token().transfer(_recipient, _amount);
}
function setErc20token(address _token) private {
require(_token != address(0));
addressStorage[keccak256(abi.encodePacked("erc20token"))] = _token;
}
}

View File

@ -0,0 +1,87 @@
pragma solidity 0.4.24;
import "../../libraries/SafeMath.sol";
import "../../libraries/Message.sol";
import "../BasicBridge.sol";
import "../../upgradeability/EternalStorage.sol";
import "../../IBlockReward.sol";
import "../../ERC677Receiver.sol";
import "../BasicHomeBridge.sol";
import "../ERC677Bridge.sol";
contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
function () public payable {
require(msg.value > 0);
require(msg.data.length == 0);
require(withinLimit(msg.value));
IBlockReward blockReward = blockRewardContract();
uint256 totalMinted = blockReward.mintedTotallyByBridge(address(this));
require(msg.value <= totalMinted.sub(totalBurntCoins()));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
setTotalBurntCoins(totalBurntCoins().add(msg.value));
address(0).transfer(msg.value);
emit UserRequestForSignature(msg.sender, msg.value);
}
function initialize (
address _validatorContract,
uint256 _dailyLimit,
uint256 _maxPerTx,
uint256 _minPerTx,
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
address _blockReward
) public returns(bool)
{
require(!isInitialized());
require(_validatorContract != address(0));
require(_requiredBlockConfirmations > 0);
require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx);
require(_blockReward == address(0) || isContract(_blockReward));
addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract;
uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number;
uintStorage[keccak256(abi.encodePacked("dailyLimit"))] = _dailyLimit;
uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx;
uintStorage[keccak256(abi.encodePacked("minPerTx"))] = _minPerTx;
uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _homeGasPrice;
uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations;
addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward;
setInitialize(true);
return isInitialized();
}
function getBridgeMode() public pure returns(bytes4 _data) {
return bytes4(keccak256(abi.encodePacked("erc-to-native-core")));
}
function blockRewardContract() public view returns(IBlockReward) {
return IBlockReward(addressStorage[keccak256(abi.encodePacked("blockRewardContract"))]);
}
function totalBurntCoins() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("totalBurntCoins"))];
}
function setBlockRewardContract(address _blockReward) public onlyOwner {
require(_blockReward != address(0) && isContract(_blockReward) && (IBlockReward(_blockReward).bridgesAllowedLength() != 0));
addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward;
}
function onExecuteAffirmation(address _recipient, uint256 _value) internal returns(bool) {
IBlockReward blockReward = blockRewardContract();
require(blockReward != address(0));
blockReward.addExtraReceiver(_value, _recipient);
return true;
}
function fireEventOnTokenTransfer(address _from, uint256 _value) internal {
emit UserRequestForSignature(_from, _value);
}
function setTotalBurntCoins(uint256 _amount) internal {
uintStorage[keccak256(abi.encodePacked("totalBurntCoins"))] = _amount;
}
}

View File

@ -2,7 +2,8 @@
BRIDGE_MODE=NATIVE_TO_ERC
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14
DEPLOYMENT_GAS_LIMIT=4000000
DEPLOYMENT_GAS_PRICE=10
HOME_DEPLOYMENT_GAS_PRICE=10000000000
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000
BRIDGEABLE_TOKEN_NAME="Your New Bridged Token"
@ -17,7 +18,10 @@ HOME_DAILY_LIMIT=30000000000000000000000000
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
HOME_MIN_AMOUNT_PER_TX=500000000000000000
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
HOME_GAS_PRICE=1
HOME_GAS_PRICE=1000000000
#for bridge erc to native mode
BLOCK_REWARD_ADDRESS=
FOREIGN_RPC_URL=https://sokol.poa.network
FOREIGN_OWNER_MULTISIG=0x
@ -27,8 +31,8 @@ FOREIGN_DAILY_LIMIT=15000000000000000000000000
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
FOREIGN_MIN_AMOUNT_PER_TX=500000000000000000
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=8
FOREIGN_GAS_PRICE=10
#for bridge erc to erc mode
FOREIGN_GAS_PRICE=10000000000
#for bridge erc_to_erc and erc_to_native mode
ERC20_TOKEN_ADDRESS=
REQUIRED_NUMBER_OF_VALIDATORS=1

28
deploy/.eslintrc Normal file
View File

@ -0,0 +1,28 @@
{
"extends": [
"plugin:node/recommended",
"airbnb-base",
"plugin:prettier/recommended"
],
"plugins": ["node"],
"rules": {
"no-var": "error",
/* "arrow-body-style": "off", */
/* "func-names": "off", */
/* "no-await-in-loop": "off", */
"consistent-return": "off",
"global-require": "off",
"no-console": "off",
/* "no-param-reassign": "off", */
"no-plusplus": "off",
/* "no-restricted-syntax": "off", */
/* "no-shadow": "off", */
"no-use-before-define": ["error", { "functions": false }],
/* "import/no-dynamic-require": "off" */
"import/no-extraneous-dependencies": "off",
"node/no-extraneous-require": ["error", {
"allowModules": ["web3-utils"]
}],
"node/no-unpublished-require": "off",
}
}

1
deploy/.nvmrc Normal file
View File

@ -0,0 +1 @@
8.9

5
deploy/.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 100
}

View File

@ -18,11 +18,11 @@ cp .env.example .env
4. Adjust the parameters in the `.env` file depending on the desired bridge mode. See below for comments related to each parameter.
5. Add funds to the deployment accounts in both the Home and Foreign networks.
5. Add funds to the deployment accounts in both theHome and Foreign networks.
6. Run `node deploy.js`.
## `NATIVE-TO-ERC` Bridge Mode Configuration Example.
## `NATIVE-TO-ERC` Bridge Mode Configuration Example.
This example of an `.env` file for the `native-to-erc` bridge mode includes comments describing each parameter.
@ -39,8 +39,11 @@ DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14
# The "gas" parameter set in every deployment/configuration transaction.
DEPLOYMENT_GAS_LIMIT=4000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# both networks.
DEPLOYMENT_GAS_PRICE=10
# Home network (in Wei).
HOME_DEPLOYMENT_GAS_PRICE=10000000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# Foreign network (in Wei).
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
# The timeout limit to wait for receipt of the deployment/configuration
# transaction.
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000
@ -63,7 +66,7 @@ HOME_OWNER_MULTISIG=0x
# The address from which a validator's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_VALIDATORS=0x
# The address from which the bridge's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_BRIDGE=0x
HOME_UPGRADEABLE_ADMIN_BRIDGE=0x
# The daily transaction limit in Wei. As soon as this limit is exceeded, any
# transaction which requests to relay assets will fail.
HOME_DAILY_LIMIT=30000000000000000000000000
@ -78,10 +81,10 @@ HOME_MIN_AMOUNT_PER_TX=500000000000000000
# the corresponding deposit transaction to guarantee the transaction will not be
# rolled back.
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
# The default gas price used to send Home Network signature transactions for
# deposit or withdrawl confirmations. This price is used if the Gas price oracle
# is unreachable.
HOME_GAS_PRICE=1
# The default gas price (in Wei) used to send Home Network signature
# transactions for deposit or withdrawal confirmations. This price is used if
# the Gas price oracle is unreachable.
HOME_GAS_PRICE=1000000000
# The RPC channel to a Foreign node able to handle deployment/configuration
# transactions.
@ -108,9 +111,10 @@ FOREIGN_MIN_AMOUNT_PER_TX=500000000000000000
# the corresponding deposit transaction to guarantee the transaction will not be
# rolled back.
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=8
# The default gas price used to send Foreign network transactions finalizing
# asset deposits. This price is used if the Gas price oracle is unreachable.
FOREIGN_GAS_PRICE=10
# The default gas price (in Wei) used to send Foreign network transactions
# finalizing asset deposits. This price is used if the Gas price oracle is
# unreachable.
FOREIGN_GAS_PRICE=10000000000
# The minimum number of validators required to send their signatures confirming
# the relay of assets. The same number of validators is expected on both sides
@ -139,8 +143,11 @@ DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14
# The "gas" parameter set in every deployment/configuration transaction.
DEPLOYMENT_GAS_LIMIT=4000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# both networks.
DEPLOYMENT_GAS_PRICE=10
# Home network (in Wei).
HOME_DEPLOYMENT_GAS_PRICE=10000000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# Foreign network (in Wei).
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
# The timeout limit to wait for receipt of the deployment/configuration
# transaction.
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000
@ -163,7 +170,100 @@ HOME_OWNER_MULTISIG=0x
# The address from which a validator's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_VALIDATORS=0x
# The address from which the bridge's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_BRIDGE=0x
HOME_UPGRADEABLE_ADMIN_BRIDGE=0x
# The daily transaction limit in Wei. As soon as this limit is exceeded, any
# transaction which requests to relay assets will fail.
HOME_DAILY_LIMIT=30000000000000000000000000
# The maximum limit for one transaction in Wei. If a single transaction tries to
# relay funds exceeding this limit it will fail.
HOME_MAX_AMOUNT_PER_TX=1500000000000000000000000
# The minimum limit for one transaction in Wei. If a transaction tries to relay
# funds below this limit it will fail. This is required to prevent dryout
# validator accounts.
HOME_MIN_AMOUNT_PER_TX=500000000000000000
# The finalization threshold. The number of blocks issued after the block with
# the corresponding deposit transaction to guarantee the transaction will not be
# rolled back.
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
# The default gas price (in Wei) used to send Home Network signature
# transactions for deposit or withdrawl confirmations. This price is used if
# the Gas price oracle is unreachable.
HOME_GAS_PRICE=1000000000
# The RPC channel to a Foreign node able to handle deployment/configuration
# transactions.
FOREIGN_RPC_URL=https://mainnet.infura.io
# The address of an administrator on the Foreign network who can change bridge
# parameters and the validator's contract. For extra security we recommended
# using a multi-sig wallet contract address here.
FOREIGN_OWNER_MULTISIG=0x
# The address from which a validator's contract can be upgraded on Foreign.
FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS=0x
# The address from which the bridge's contract can be upgraded on Foreign.
FOREIGN_UPGRADEABLE_ADMIN_BRIDGE=0x
# These three parameters are not used in this mode, but the deployment script
# requires it to be set to some value.
FOREIGN_DAILY_LIMIT=15000000000000000000000000
FOREIGN_MAX_AMOUNT_PER_TX=750000000000000000000000
FOREIGN_MIN_AMOUNT_PER_TX=500000000000000000
# The finalization threshold. The number of blocks issued after the block with
# the corresponding deposit transaction to guarantee the transaction will not be
# rolled back.
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=8
# The default gas price (in Wei) used to send Foreign network transactions
# finalizing asset deposits. This price is used if the Gas price oracle is
# unreachable.
FOREIGN_GAS_PRICE=10000000000
# The address of the existing ERC20 compatible token in the Foreign network to
# be exchanged to the ERC20/ERC677 token deployed on Home.
ERC20_TOKEN_ADDRESS=0x
# The minimum number of validators required to send their signatures confirming
# the relay of assets. The same number of validators is expected on both sides
# of the bridge.
REQUIRED_NUMBER_OF_VALIDATORS=1
# The set of validators' addresses. It is assumed that signatures from these
# addresses are collected on the Home side. The same addresses will be used on
# the Foreign network to confirm that the finalized agreement was transferred
# correctly to the Foreign network.
VALIDATORS="0x 0x 0x"
```
## `ERC-TO-NATIVE` Bridge Mode Configuration Example.
This example of an `.env` file for the `erc-to-native` bridge mode includes comments describing each parameter.
```bash
# The type of bridge. Defines set of contracts to be deployed.
BRIDGE_MODE=ERC_TO_NATIVE
# The private key hex value of the account responsible for contracts
# deployments and initial configuration. The account's balance must contain
# funds from both networks.
DEPLOYMENT_ACCOUNT_PRIVATE_KEY=67..14
# The "gas" parameter set in every deployment/configuration transaction.
DEPLOYMENT_GAS_LIMIT=4000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# home network.
HOME_DEPLOYMENT_GAS_PRICE=10000000000
# The "gasPrice" parameter set in every deployment/configuration transaction on
# foreign network.
FOREIGN_DEPLOYMENT_GAS_PRICE=10000000000
# The timeout limit to wait for receipt of the deployment/configuration
# transaction.
GET_RECEIPT_INTERVAL_IN_MILLISECONDS=3000
# The RPC channel to a Home node able to handle deployment/configuration
# transactions.
HOME_RPC_URL=https://poa.infura.io
# The address of an administrator on the Home network who can change bridge
# parameters and a validator's contract. For extra security we recommended using
# a multi-sig wallet contract address here.
HOME_OWNER_MULTISIG=0x
# The address from which a validator's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_VALIDATORS=0x
# The address from which the bridge's contract can be upgraded on Home.
HOME_UPGRADEABLE_ADMIN_BRIDGE=0x
# The daily transaction limit in Wei. As soon as this limit is exceeded, any
# transaction which requests to relay assets will fail.
HOME_DAILY_LIMIT=30000000000000000000000000
@ -180,9 +280,12 @@ HOME_MIN_AMOUNT_PER_TX=500000000000000000
HOME_REQUIRED_BLOCK_CONFIRMATIONS=1
# The default gas price used to send Home Network signature transactions for
# deposit or withdrawl confirmations. This price is used if the Gas price oracle
# is unreachable.
# is unreachable.
HOME_GAS_PRICE=1
# The address of the existing smart contract for block reward calculation on Home network.
BLOCK_REWARD_ADDRESS=0x
# The RPC channel to a Foreign node able to handle deployment/configuration
# transactions.
FOREIGN_RPC_URL=https://mainnet.infura.io
@ -206,8 +309,9 @@ FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS=8
# The default gas price used to send Foreign network transactions finalizing
# asset deposits. This price is used if the Gas price oracle is unreachable.
FOREIGN_GAS_PRICE=10
# The address of the existing ERC20 compatible token in the Foreign network to
# be exchanged to the ERC20/ERC677 token deployed on Home.
# be exchanged to the native coins on Home.
ERC20_TOKEN_ADDRESS=0x
# The minimum number of validators required to send their signatures confirming

View File

@ -1,66 +1,131 @@
const fs = require('fs');
const fs = require('fs')
const path = require('path')
require('dotenv').config({
path: path.join(__dirname, '.env')
});
const env = require('./src/loadEnv')
const { ZERO_ADDRESS } = require('./src/constants')
const { BRIDGE_MODE, BLOCK_REWARD_ADDRESS, ERC20_TOKEN_ADDRESS } = env
const deployResultsPath = path.join(__dirname, './bridgeDeploymentResults.json')
async function deployNativeToErc(){
const deployHome = require('./src/native_to_erc/home');
const deployForeign = require('./src/native_to_erc/foreign');
async function deployNativeToErc() {
const deployHome = require('./src/native_to_erc/home')
const deployForeign = require('./src/native_to_erc/foreign')
const homeBridge = await deployHome()
const {foreignBridge, erc677} = await deployForeign();
console.log("\nDeployment has been completed.\n\n")
console.log(`[ Home ] HomeBridge: ${homeBridge.address} at block ${homeBridge.deployedBlockNumber}`)
console.log(`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${foreignBridge.deployedBlockNumber}`)
const { foreignBridge, erc677 } = await deployForeign()
console.log('\nDeployment has been completed.\n\n')
console.log(
`[ Home ] HomeBridge: ${homeBridge.address} at block ${homeBridge.deployedBlockNumber}`
)
console.log(
`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${
foreignBridge.deployedBlockNumber
}`
)
console.log(`[ Foreign ] POA20: ${erc677.address}`)
fs.writeFileSync(deployResultsPath, JSON.stringify({
homeBridge: {
...homeBridge,
},foreignBridge: {
...foreignBridge,
},erc677
},null,4));
fs.writeFileSync(
deployResultsPath,
JSON.stringify(
{
homeBridge: {
...homeBridge
},
foreignBridge: {
...foreignBridge
},
erc677
},
null,
4
)
)
console.log('Contracts Deployment have been saved to `bridgeDeploymentResults.json`')
}
async function deployErcToErc() {
const deployHome = require('./src/erc_to_erc/home');
const deployForeign = require('./src/erc_to_erc/foreign');
const deployHome = require('./src/erc_to_erc/home')
const deployForeign = require('./src/erc_to_erc/foreign')
const {homeBridgeAddress, erc677tokenAddress, deployedBlockNumber} = await deployHome()
const {foreignBridge} = await deployForeign();
console.log("\nDeployment has been completed.\n\n")
const { homeBridgeAddress, erc677tokenAddress, deployedBlockNumber } = await deployHome()
const { foreignBridge } = await deployForeign()
console.log('\nDeployment has been completed.\n\n')
console.log(`[ Home ] HomeBridge: ${homeBridgeAddress} at block ${deployedBlockNumber}`)
console.log(`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${foreignBridge.deployedBlockNumber}`)
console.log(`[ Foreign ] ERC20 Token: ${process.env.ERC20_TOKEN_ADDRESS}`)
console.log(
`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${
foreignBridge.deployedBlockNumber
}`
)
console.log(`[ Foreign ] ERC20 Token: ${ERC20_TOKEN_ADDRESS}`)
console.log(`[ Home ] ERC677 Bridgeble Token: ${erc677tokenAddress}`)
fs.writeFileSync(deployResultsPath, JSON.stringify({
homeBridge: {
homeBridgeAddress,
erc677tokenAddress
},foreignBridge: {
...foreignBridge,
}
},null,4));
fs.writeFileSync(
deployResultsPath,
JSON.stringify(
{
homeBridge: {
homeBridgeAddress,
erc677tokenAddress
},
foreignBridge: {
...foreignBridge
}
},
null,
4
)
)
console.log('Contracts Deployment have been saved to `bridgeDeploymentResults.json`')
}
async function deployErcToNative() {
const deployHome = require('./src/erc_to_native/home')
const deployForeign = require('./src/erc_to_native/foreign')
const homeBridge = await deployHome()
const { foreignBridge } = await deployForeign()
console.log('\nDeployment has been completed.\n\n')
console.log(
`[ Home ] HomeBridge: ${homeBridge.homeBridgeAddress} at block ${
homeBridge.deployedBlockNumber
}`
)
console.log(
`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${
foreignBridge.deployedBlockNumber
}`
)
fs.writeFileSync(
deployResultsPath,
JSON.stringify(
{
homeBridge: {
...homeBridge
},
foreignBridge: {
...foreignBridge
}
},
null,
4
)
)
console.log('Contracts Deployment have been saved to `bridgeDeploymentResults.json`')
}
async function main() {
const BRIDGE_MODE = process.env.BRIDGE_MODE;
console.log(`Bridge mode: ${BRIDGE_MODE}`)
switch(BRIDGE_MODE) {
case "NATIVE_TO_ERC":
await deployNativeToErc();
break;
case "ERC_TO_ERC":
await deployErcToErc();
break;
switch (BRIDGE_MODE) {
case 'NATIVE_TO_ERC':
await deployNativeToErc()
break
case 'ERC_TO_ERC':
await deployErcToErc()
break
case 'ERC_TO_NATIVE':
await deployErcToNative()
break
default:
console.log(BRIDGE_MODE)
throw "Please specify BRIDGE_MODE: NATIVE_TO_ERC or ERC_TO_ERC"
throw new Error('Please specify BRIDGE_MODE: NATIVE_TO_ERC or ERC_TO_ERC')
}
}

2309
deploy/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,15 +4,29 @@
"description": "",
"main": "deploy.js",
"scripts": {
"compile": "pkg deploy.js --out-path build/tmp_build"
"compile": "pkg deploy.js --out-path build/tmp_build",
"lint": "eslint ."
},
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^5.0.1",
"envalid": "^4.1.4",
"ethereumjs-tx": "^1.3.4",
"node-fetch": "^2.1.2",
"pkg": "^4.3.1",
"web3": "^1.0.0-beta.33"
},
"devDependencies": {
"eslint": "^5.6.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.0.1",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-prettier": "^2.6.2",
"prettier": "^1.14.3"
},
"engines": {
"node": ">= 8.9"
}
}

5
deploy/src/constants.js Normal file
View File

@ -0,0 +1,5 @@
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
module.exports = {
ZERO_ADDRESS
}

View File

@ -1,4 +1,8 @@
const Web3 = require('web3')
const Tx = require('ethereumjs-tx')
const Web3Utils = require('web3-utils')
const fetch = require('node-fetch')
const assert = require('assert')
const {
web3Home,
web3Foreign,
@ -6,103 +10,122 @@ const {
FOREIGN_RPC_URL,
HOME_RPC_URL,
GAS_LIMIT,
GAS_PRICE,
HOME_DEPLOYMENT_GAS_PRICE,
FOREIGN_DEPLOYMENT_GAS_PRICE,
GET_RECEIPT_INTERVAL_IN_MILLISECONDS
} = require('./web3');
const Tx = require('ethereumjs-tx');
const Web3Utils = require('web3-utils');
const fetch = require('node-fetch');
const assert = require('assert')
} = require('./web3')
async function deployContract(contractJson, args, {from, network, nonce}) {
let web3, url;
if(network === 'foreign'){
async function deployContract(contractJson, args, { from, network, nonce }) {
let web3
let url
let gasPrice
if (network === 'foreign') {
web3 = web3Foreign
url = FOREIGN_RPC_URL
gasPrice = FOREIGN_DEPLOYMENT_GAS_PRICE
} else {
web3 = web3Home
url = HOME_RPC_URL
gasPrice = HOME_DEPLOYMENT_GAS_PRICE
}
const options = {
from,
gasPrice: GAS_PRICE,
};
let instance = new web3.eth.Contract(contractJson.abi, options);
const result = await instance.deploy({
data: contractJson.bytecode,
arguments: args
}).encodeABI()
from
}
const instance = new web3.eth.Contract(contractJson.abi, options)
const result = await instance
.deploy({
data: contractJson.bytecode,
arguments: args
})
.encodeABI()
const tx = await sendRawTx({
data: result,
nonce: Web3Utils.toHex(nonce),
to: null,
privateKey: deploymentPrivateKey,
url
url,
gasPrice: gasPrice
})
if(tx.status !== '0x1'){
throw new Error('Tx failed');
if (tx.status !== '0x1') {
throw new Error('Tx failed')
}
instance.options.address = tx.contractAddress;
instance.options.address = tx.contractAddress
instance.deployedBlockNumber = tx.blockNumber
return instance;
return instance
}
async function sendRawTxHome(options) {
return sendRawTx({
...options,
gasPrice: HOME_DEPLOYMENT_GAS_PRICE
})
}
async function sendRawTx({data, nonce, to, privateKey, url}) {
async function sendRawTxForeign(options) {
return sendRawTx({
...options,
gasPrice: FOREIGN_DEPLOYMENT_GAS_PRICE
})
}
async function sendRawTx({ data, nonce, to, privateKey, url, gasPrice, value }) {
try {
var rawTx = {
const rawTx = {
nonce,
gasPrice: Web3Utils.toHex(GAS_PRICE),
gasPrice: Web3Utils.toHex(gasPrice),
gasLimit: Web3Utils.toHex(GAS_LIMIT),
to,
data
data,
value
}
var tx = new Tx(rawTx);
tx.sign(privateKey);
var serializedTx = tx.serialize();
const txHash = await sendNodeRequest(url, "eth_sendRawTransaction", '0x' + serializedTx.toString('hex'));
console.log('pending txHash', txHash );
const receipt = await getReceipt(txHash, url);
const tx = new Tx(rawTx)
tx.sign(privateKey)
const serializedTx = tx.serialize()
const txHash = await sendNodeRequest(
url,
'eth_sendRawTransaction',
`0x${serializedTx.toString('hex')}`
)
console.log('pending txHash', txHash)
const receipt = await getReceipt(txHash, url)
return receipt
} catch (e) {
console.error(e)
}
}
async function sendNodeRequest(url, method, signedData){
async function sendNodeRequest(url, method, signedData) {
const request = await fetch(url, {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
jsonrpc: "2.0",
jsonrpc: '2.0',
method,
params: [signedData],
id: 1
})
});
})
const json = await request.json()
if(method === 'eth_sendRawTransaction') {
if (method === 'eth_sendRawTransaction') {
assert.equal(json.result.length, 66, `Tx wasn't sent ${json}`)
}
return json.result;
return json.result
}
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
return new Promise(resolve => setTimeout(resolve, ms))
}
async function getReceipt(txHash, url) {
await timeout(GET_RECEIPT_INTERVAL_IN_MILLISECONDS);
let receipt = await sendNodeRequest(url, "eth_getTransactionReceipt", txHash);
if(receipt === null || receipt.blockNumber === null) {
receipt = await getReceipt(txHash, url);
await timeout(GET_RECEIPT_INTERVAL_IN_MILLISECONDS)
let receipt = await sendNodeRequest(url, 'eth_getTransactionReceipt', txHash)
if (receipt === null || receipt.blockNumber === null) {
receipt = await getReceipt(txHash, url)
}
return receipt;
return receipt
}
function add0xPrefix(s) {
@ -110,7 +133,7 @@ function add0xPrefix(s) {
return s
}
return '0x' + s
return `0x${s}`
}
function privateKeyToAddress(privateKey) {
@ -122,5 +145,7 @@ module.exports = {
sendNodeRequest,
getReceipt,
sendRawTx,
sendRawTxHome,
sendRawTxForeign,
privateKeyToAddress
}

View File

@ -1,18 +1,15 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
require('dotenv').config({
path: __dirname + '../../.env'
});
const env = require('../loadEnv')
const assert = require('assert');
const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils')
const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3')
const {deployContract, privateKeyToAddress, sendRawTx} = require('../deploymentUtils');
const {web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL} = require('../web3');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const ForeignBridge = require('../../../build/contracts/ForeignBridgeErcToErc.json')
const VALIDATORS = process.env.VALIDATORS.split(" ")
const VALIDATORS = env.VALIDATORS.split(' ')
const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
@ -21,131 +18,164 @@ const {
FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS,
FOREIGN_UPGRADEABLE_ADMIN_BRIDGE,
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
ERC20_TOKEN_ADDRESS
} = process.env;
ERC20_TOKEN_ADDRESS,
FOREIGN_GAS_PRICE
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployForeign() {
if(!Web3Utils.isAddress(ERC20_TOKEN_ADDRESS)){
throw "ERC20_TOKEN_ADDRESS env var is not defined"
if (!Web3Utils.isAddress(ERC20_TOKEN_ADDRESS)) {
throw new Error('ERC20_TOKEN_ADDRESS env var is not defined')
}
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS);
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('========================================')
console.log('deploying ForeignBridge')
console.log('========================================\n')
console.log('deploying storage for foreign validators')
const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address)
console.log('\ndeploying implementation for foreign validators')
let bridgeValidatorsForeign = await deployContract(BridgeValidators, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
console.log('[Foreign] BridgeValidators Implementation: ', bridgeValidatorsForeign.options.address)
const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] BridgeValidators Implementation: ',
bridgeValidatorsForeign.options.address
)
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods.upgradeTo('1', bridgeValidatorsForeign.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToBridgeVForeign = await sendRawTx({
const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods
.upgradeTo('1', bridgeValidatorsForeign.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVForeign = await sendRawTxForeign({
data: upgradeToBridgeVForeignData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txUpgradeToBridgeVForeign.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txUpgradeToBridgeVForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge Validators with following parameters:\n')
console.log(`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`)
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address
const initializeForeignData = await bridgeValidatorsForeign.methods.initialize(
REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_OWNER_MULTISIG
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeForeign = await sendRawTx({
const initializeForeignData = await bridgeValidatorsForeign.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeForeign = await sendRawTxForeign({
data: initializeForeignData,
nonce: foreignNonce,
to: bridgeValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txInitializeForeign.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txInitializeForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\nTransferring ownership of ValidatorsProxy\n')
const validatorsForeignOwnershipData = await storageValidatorsForeign.methods.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txValidatorsForeignOwnershipData = await sendRawTx({
const validatorsForeignOwnershipData = await storageValidatorsForeign.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txValidatorsForeignOwnershipData = await sendRawTxForeign({
data: validatorsForeignOwnershipData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txValidatorsForeignOwnershipData.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txValidatorsForeignOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ndeploying foreignBridge storage\n')
const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address)
console.log('\ndeploying foreignBridge implementation\n')
const foreignBridgeImplementation = await deployContract(ForeignBridge, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
console.log('[Foreign] ForeignBridge Implementation: ', foreignBridgeImplementation.options.address)
const foreignBridgeImplementation = await deployContract(ForeignBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] ForeignBridge Implementation: ',
foreignBridgeImplementation.options.address
)
console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation')
const upgradeToForeignBridgeData = await foreignBridgeStorage.methods.upgradeTo('1', foreignBridgeImplementation.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToForeignBridge = await sendRawTx({
const upgradeToForeignBridgeData = await foreignBridgeStorage.methods
.upgradeTo('1', foreignBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToForeignBridge = await sendRawTxForeign({
data: upgradeToForeignBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txUpgradeToForeignBridge.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txUpgradeToForeignBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge with following parameters:\n')
console.log(`Foreign Validators: ${storageValidatorsForeign.options.address},
`)
foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address
const initializeFBridgeData = await foreignBridgeImplementation.methods.initialize(
storageValidatorsForeign.options.address, ERC20_TOKEN_ADDRESS, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeBridge = await sendRawTx({
const initializeFBridgeData = await foreignBridgeImplementation.methods
.initialize(
storageValidatorsForeign.options.address,
ERC20_TOKEN_ADDRESS,
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
FOREIGN_GAS_PRICE
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeBridge = await sendRawTxForeign({
data: initializeFBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txInitializeBridge.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txInitializeBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
const bridgeOwnershipData = await foreignBridgeStorage.methods.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txBridgeOwnershipData = await sendRawTx({
const bridgeOwnershipData = await foreignBridgeStorage.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txBridgeOwnershipData = await sendRawTxForeign({
data: bridgeOwnershipData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txBridgeOwnershipData.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txBridgeOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
return {
foreignBridge:
{
address: foreignBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(foreignBridgeStorage.deployedBlockNumber)
}
foreignBridge: {
address: foreignBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(foreignBridgeStorage.deployedBlockNumber)
}
}
}
module.exports = deployForeign;
module.exports = deployForeign

View File

@ -1,20 +1,16 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
require('dotenv').config({
path: __dirname + '../../.env'
});
const env = require('../loadEnv')
const assert = require('assert');
const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils')
const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3')
const {deployContract, privateKeyToAddress, sendRawTx} = require('../deploymentUtils');
const {web3Home, deploymentPrivateKey, HOME_RPC_URL} = require('../web3');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const HomeBridge = require('../../../build/contracts/HomeBridgeErcToErc.json')
const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json');
const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json')
const VALIDATORS = process.env.VALIDATORS.split(" ")
const HOME_GAS_PRICE = Web3Utils.toWei(process.env.HOME_GAS_PRICE, 'gwei');
const VALIDATORS = env.VALIDATORS.split(' ')
const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
@ -26,150 +22,191 @@ const {
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_REQUIRED_BLOCK_CONFIRMATIONS,
HOME_GAS_PRICE,
BRIDGEABLE_TOKEN_NAME,
BRIDGEABLE_TOKEN_SYMBOL,
BRIDGEABLE_TOKEN_DECIMALS,
} = process.env;
BRIDGEABLE_TOKEN_DECIMALS
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployHome()
{
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS);
async function deployHome() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('deploying storage for home validators')
const storageValidatorsHome = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
const storageValidatorsHome = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address)
homeNonce++;
homeNonce++
console.log('\ndeploying implementation for home validators')
let bridgeValidatorsHome = await deployContract(BridgeValidators, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
const bridgeValidatorsHome = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address)
homeNonce++;
homeNonce++
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVHomeData = await storageValidatorsHome.methods.upgradeTo('1', bridgeValidatorsHome.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToBridgeVHome = await sendRawTx({
const upgradeToBridgeVHomeData = await storageValidatorsHome.methods
.upgradeTo('1', bridgeValidatorsHome.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVHome = await sendRawTxHome({
data: upgradeToBridgeVHomeData,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToBridgeVHome.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txUpgradeToBridgeVHome.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge Validators with following parameters:\n')
console.log(`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`)
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsHome.options.address = storageValidatorsHome.options.address
const initializeData = await bridgeValidatorsHome.methods.initialize(
REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_OWNER_MULTISIG
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS})
const txInitialize = await sendRawTx({
const initializeData = await bridgeValidatorsHome.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitialize = await sendRawTxHome({
data: initializeData,
nonce: homeNonce,
to: bridgeValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txInitialize.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txInitialize.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Validators Proxy contract');
const proxyDataTransfer = await storageValidatorsHome.methods.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_VALIDATORS).encodeABI();
const txProxyDataTransfer = await sendRawTx({
console.log('transferring proxy ownership to multisig for Validators Proxy contract')
const proxyDataTransfer = await storageValidatorsHome.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI()
const txProxyDataTransfer = await sendRawTxHome({
data: proxyDataTransfer,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txProxyDataTransfer.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txProxyDataTransfer.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ndeploying homeBridge storage\n')
const homeBridgeStorage = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
homeNonce++;
const homeBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address)
console.log('\ndeploying homeBridge implementation\n')
const homeBridgeImplementation = await deployContract(HomeBridge, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
homeNonce++;
const homeBridgeImplementation = await deployContract(HomeBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address)
console.log('\nhooking up HomeBridge storage to HomeBridge implementation')
const upgradeToHomeBridgeData = await homeBridgeStorage.methods.upgradeTo('1', homeBridgeImplementation.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToHomeBridge = await sendRawTx({
const upgradeToHomeBridgeData = await homeBridgeStorage.methods
.upgradeTo('1', homeBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToHomeBridge = await sendRawTxHome({
data: upgradeToHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToHomeBridge.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txUpgradeToHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\n[Home] deploying Bridgeble token')
const erc677token = await deployContract(ERC677BridgeToken,
const erc677token = await deployContract(
ERC677BridgeToken,
[BRIDGEABLE_TOKEN_NAME, BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS],
{from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'home', nonce: homeNonce}
{ from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'home', nonce: homeNonce }
)
homeNonce++;
homeNonce++
console.log('[Home] Bridgeble Token: ', erc677token.options.address)
console.log('\nset bridge contract on ERC677BridgeToken')
const setBridgeContractData = await erc677token.methods
.setBridgeContract(homeBridgeStorage.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const setBridgeContract = await sendRawTxHome({
data: setBridgeContractData,
nonce: homeNonce,
to: erc677token.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(setBridgeContract.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring ownership of Bridgeble token to homeBridge contract')
const txOwnershipData = await erc677token.methods.transferOwnership(homeBridgeStorage.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS})
const txOwnership = await sendRawTx({
const txOwnershipData = await erc677token.methods
.transferOwnership(homeBridgeStorage.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txOwnership = await sendRawTxHome({
data: txOwnershipData,
nonce: homeNonce,
to: erc677token.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
});
assert.equal(txOwnership.status, '0x1', 'Transaction Failed');
homeNonce++;
})
assert.equal(txOwnership.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge with following parameters:\n')
console.log(`Home Validators: ${storageValidatorsHome.options.address},
HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth,
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(HOME_MAX_AMOUNT_PER_TX)} in eth,
HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(HOME_MIN_AMOUNT_PER_TX)} in eth,
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MAX_AMOUNT_PER_TX
)} in eth,
HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MIN_AMOUNT_PER_TX
)} in eth,
HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}
`)
homeBridgeImplementation.options.address = homeBridgeStorage.options.address
const initializeHomeBridgeData = await homeBridgeImplementation.methods.initialize(
storageValidatorsHome.options.address,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_GAS_PRICE,
HOME_REQUIRED_BLOCK_CONFIRMATIONS,
erc677token.options.address
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeHomeBridge = await sendRawTx({
const initializeHomeBridgeData = await homeBridgeImplementation.methods
.initialize(
storageValidatorsHome.options.address,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_GAS_PRICE,
HOME_REQUIRED_BLOCK_CONFIRMATIONS,
erc677token.options.address
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeHomeBridge = await sendRawTxHome({
data: initializeHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
});
assert.equal(txInitializeHomeBridge.status, '0x1', 'Transaction Failed');
homeNonce++;
})
assert.equal(txInitializeHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Home bridge Proxy contract');
const homeBridgeProxyData = await homeBridgeStorage.methods.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_BRIDGE).encodeABI();
const txhomeBridgeProxyData = await sendRawTx({
console.log('transferring proxy ownership to multisig for Home bridge Proxy contract')
const homeBridgeProxyData = await homeBridgeStorage.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI()
const txhomeBridgeProxyData = await sendRawTxHome({
data: homeBridgeProxyData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txhomeBridgeProxyData.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txhomeBridgeProxyData.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\nHome Deployment Bridge is complete\n')
return {
@ -177,6 +214,5 @@ async function deployHome()
erc677tokenAddress: erc677token.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(homeBridgeStorage.deployedBlockNumber)
}
}
module.exports = deployHome;
module.exports = deployHome

View File

@ -0,0 +1,181 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
const env = require('../loadEnv')
const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils')
const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3')
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const ForeignBridge = require('../../../build/contracts/ForeignBridgeErcToNative.json')
const VALIDATORS = env.VALIDATORS.split(' ')
const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
REQUIRED_NUMBER_OF_VALIDATORS,
FOREIGN_GAS_PRICE,
FOREIGN_OWNER_MULTISIG,
FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS,
FOREIGN_UPGRADEABLE_ADMIN_BRIDGE,
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
ERC20_TOKEN_ADDRESS
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployForeign() {
if (!Web3Utils.isAddress(ERC20_TOKEN_ADDRESS)) {
throw new Error('ERC20_TOKEN_ADDRESS env var is not defined')
}
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('========================================')
console.log('deploying ForeignBridge')
console.log('========================================\n')
console.log('deploying storage for foreign validators')
const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address)
console.log('\ndeploying implementation for foreign validators')
const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] BridgeValidators Implementation: ',
bridgeValidatorsForeign.options.address
)
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods
.upgradeTo('1', bridgeValidatorsForeign.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVForeign = await sendRawTxForeign({
data: upgradeToBridgeVForeignData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txUpgradeToBridgeVForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge Validators with following parameters:\n')
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address
const initializeForeignData = await bridgeValidatorsForeign.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeForeign = await sendRawTxForeign({
data: initializeForeignData,
nonce: foreignNonce,
to: bridgeValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txInitializeForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\nTransferring ownership of ValidatorsProxy\n')
const validatorsForeignOwnershipData = await storageValidatorsForeign.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txValidatorsForeignOwnershipData = await sendRawTxForeign({
data: validatorsForeignOwnershipData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txValidatorsForeignOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ndeploying foreignBridge storage\n')
const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address)
console.log('\ndeploying foreignBridge implementation\n')
const foreignBridgeImplementation = await deployContract(ForeignBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] ForeignBridge Implementation: ',
foreignBridgeImplementation.options.address
)
console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation')
const upgradeToForeignBridgeData = await foreignBridgeStorage.methods
.upgradeTo('1', foreignBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToForeignBridge = await sendRawTxForeign({
data: upgradeToForeignBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txUpgradeToForeignBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge with following parameters:\n')
console.log(`Foreign Validators: ${storageValidatorsForeign.options.address},
`)
foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address
const initializeFBridgeData = await foreignBridgeImplementation.methods
.initialize(
storageValidatorsForeign.options.address,
ERC20_TOKEN_ADDRESS,
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
FOREIGN_GAS_PRICE
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeBridge = await sendRawTxForeign({
data: initializeFBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txInitializeBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
const bridgeOwnershipData = await foreignBridgeStorage.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txBridgeOwnershipData = await sendRawTxForeign({
data: bridgeOwnershipData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(txBridgeOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
return {
foreignBridge: {
address: foreignBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(foreignBridgeStorage.deployedBlockNumber)
}
}
}
module.exports = deployForeign

View File

@ -0,0 +1,176 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
const env = require('../loadEnv')
const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils')
const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3')
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const HomeBridge = require('../../../build/contracts/HomeBridgeErcToNative.json')
const VALIDATORS = env.VALIDATORS.split(' ')
const {
BLOCK_REWARD_ADDRESS,
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
REQUIRED_NUMBER_OF_VALIDATORS,
HOME_GAS_PRICE,
HOME_OWNER_MULTISIG,
HOME_UPGRADEABLE_ADMIN_VALIDATORS,
HOME_UPGRADEABLE_ADMIN_BRIDGE,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_REQUIRED_BLOCK_CONFIRMATIONS
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployHome() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('deploying storage for home validators')
const storageValidatorsHome = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address)
homeNonce++
console.log('\ndeploying implementation for home validators')
const bridgeValidatorsHome = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address)
homeNonce++
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVHomeData = await storageValidatorsHome.methods
.upgradeTo('1', bridgeValidatorsHome.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVHome = await sendRawTxHome({
data: upgradeToBridgeVHomeData,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToBridgeVHome.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge Validators with following parameters:\n')
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsHome.options.address = storageValidatorsHome.options.address
const initializeData = await bridgeValidatorsHome.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitialize = await sendRawTxHome({
data: initializeData,
nonce: homeNonce,
to: bridgeValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txInitialize.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Validators Proxy contract')
const proxyDataTransfer = await storageValidatorsHome.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI()
const txProxyDataTransfer = await sendRawTxHome({
data: proxyDataTransfer,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txProxyDataTransfer.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ndeploying homeBridge storage\n')
const homeBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address)
console.log('\ndeploying homeBridge implementation\n')
const homeBridgeImplementation = await deployContract(HomeBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address)
console.log('\nhooking up HomeBridge storage to HomeBridge implementation')
const upgradeToHomeBridgeData = await homeBridgeStorage.methods
.upgradeTo('1', homeBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToHomeBridge = await sendRawTxHome({
data: upgradeToHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge with following parameters:\n')
console.log(`Home Validators: ${storageValidatorsHome.options.address},
HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth,
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MAX_AMOUNT_PER_TX
)} in eth,
HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MIN_AMOUNT_PER_TX
)} in eth,
HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}`)
homeBridgeImplementation.options.address = homeBridgeStorage.options.address
const initializeHomeBridgeData = await homeBridgeImplementation.methods
.initialize(
storageValidatorsHome.options.address,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_GAS_PRICE,
HOME_REQUIRED_BLOCK_CONFIRMATIONS,
BLOCK_REWARD_ADDRESS
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeHomeBridge = await sendRawTxHome({
data: initializeHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txInitializeHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Home bridge Proxy contract')
const homeBridgeProxyData = await homeBridgeStorage.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI()
const txhomeBridgeProxyData = await sendRawTxHome({
data: homeBridgeProxyData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txhomeBridgeProxyData.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\nHome Deployment Bridge is complete\n')
return {
homeBridgeAddress: homeBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(homeBridgeStorage.deployedBlockNumber)
}
}
module.exports = deployHome

88
deploy/src/loadEnv.js Normal file
View File

@ -0,0 +1,88 @@
const path = require('path')
require('dotenv').config({
path: path.join(__dirname, '..', '.env')
})
const { isAddress, toBN } = require('web3').utils
const envalid = require('envalid')
const { ZERO_ADDRESS } = require('./constants')
// Validations and constants
const validBridgeModes = ['NATIVE_TO_ERC', 'ERC_TO_ERC', 'ERC_TO_NATIVE']
const bigNumValidator = envalid.makeValidator(x => toBN(x))
const validateAddress = address => {
if (isAddress(address)) {
return address
}
throw new Error(`Invalid address: ${address}`)
}
const addressValidator = envalid.makeValidator(validateAddress)
const addressesValidator = envalid.makeValidator(addresses => {
addresses.split(' ').forEach(validateAddress)
return addresses
})
const { BRIDGE_MODE } = process.env
if (!validBridgeModes.includes(BRIDGE_MODE)) {
throw new Error(`Invalid bridge mode: ${BRIDGE_MODE}`)
}
let validations = {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY: envalid.str(),
DEPLOYMENT_GAS_LIMIT: bigNumValidator(),
HOME_DEPLOYMENT_GAS_PRICE: bigNumValidator(),
FOREIGN_DEPLOYMENT_GAS_PRICE: bigNumValidator(),
GET_RECEIPT_INTERVAL_IN_MILLISECONDS: bigNumValidator(),
HOME_RPC_URL: envalid.str(),
HOME_OWNER_MULTISIG: addressValidator(),
HOME_UPGRADEABLE_ADMIN_VALIDATORS: addressesValidator(),
HOME_UPGRADEABLE_ADMIN_BRIDGE: addressValidator(),
HOME_DAILY_LIMIT: bigNumValidator(),
HOME_MAX_AMOUNT_PER_TX: bigNumValidator(),
HOME_MIN_AMOUNT_PER_TX: bigNumValidator(),
HOME_REQUIRED_BLOCK_CONFIRMATIONS: envalid.num(),
HOME_GAS_PRICE: bigNumValidator(),
FOREIGN_RPC_URL: envalid.str(),
FOREIGN_OWNER_MULTISIG: addressValidator(),
FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS: addressValidator(),
FOREIGN_UPGRADEABLE_ADMIN_BRIDGE: addressValidator(),
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS: envalid.num(),
FOREIGN_GAS_PRICE: bigNumValidator(),
REQUIRED_NUMBER_OF_VALIDATORS: envalid.num(),
VALIDATORS: addressesValidator()
}
if (BRIDGE_MODE === 'NATIVE_TO_ERC') {
validations = {
...validations,
BRIDGEABLE_TOKEN_NAME: envalid.str(),
BRIDGEABLE_TOKEN_SYMBOL: envalid.str(),
BRIDGEABLE_TOKEN_DECIMALS: envalid.num(),
FOREIGN_DAILY_LIMIT: bigNumValidator(),
FOREIGN_MAX_AMOUNT_PER_TX: bigNumValidator(),
FOREIGN_MIN_AMOUNT_PER_TX: bigNumValidator()
}
}
if (BRIDGE_MODE === 'ERC_TO_ERC') {
validations = {
...validations,
ERC20_TOKEN_ADDRESS: addressValidator(),
BRIDGEABLE_TOKEN_NAME: envalid.str(),
BRIDGEABLE_TOKEN_SYMBOL: envalid.str(),
BRIDGEABLE_TOKEN_DECIMALS: envalid.num()
}
}
if (BRIDGE_MODE === 'ERC_TO_NATIVE') {
validations = {
...validations,
ERC20_TOKEN_ADDRESS: addressValidator(),
BLOCK_REWARD_ADDRESS: addressValidator({
default: ZERO_ADDRESS
})
}
}
const env = envalid.cleanEnv(process.env, validations)
module.exports = env

View File

@ -1,24 +1,21 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
require('dotenv').config({
path: __dirname + '../../.env'
});
const env = require('../loadEnv')
const assert = require('assert');
const { deployContract, privateKeyToAddress, sendRawTxForeign } = require('../deploymentUtils')
const { web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL } = require('../web3')
const {deployContract, privateKeyToAddress, sendRawTx} = require('../deploymentUtils');
const {web3Foreign, deploymentPrivateKey, FOREIGN_RPC_URL} = require('../web3');
const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json');
const ERC677BridgeToken = require('../../../build/contracts/ERC677BridgeToken.json')
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const ForeignBridge = require('../../../build/contracts/ForeignBridgeNativeToErc.json')
const VALIDATORS = process.env.VALIDATORS.split(" ")
const FOREIGN_GAS_PRICE = Web3Utils.toWei(process.env.FOREIGN_GAS_PRICE, 'gwei');
const VALIDATORS = env.VALIDATORS.split(' ')
const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
REQUIRED_NUMBER_OF_VALIDATORS,
FOREIGN_GAS_PRICE,
FOREIGN_OWNER_MULTISIG,
FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS,
FOREIGN_UPGRADEABLE_ADMIN_BRIDGE,
@ -28,152 +25,210 @@ const {
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
BRIDGEABLE_TOKEN_NAME,
BRIDGEABLE_TOKEN_SYMBOL,
BRIDGEABLE_TOKEN_DECIMALS,
} = process.env;
BRIDGEABLE_TOKEN_DECIMALS
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployForeign() {
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS);
let foreignNonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('========================================')
console.log('deploying ForeignBridge')
console.log('========================================\n')
console.log('\n[Foreign] deploying BRIDGEABLE_TOKEN_SYMBOL token')
const erc677bridgeToken = await deployContract(ERC677BridgeToken, [BRIDGEABLE_TOKEN_NAME, BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
const erc677bridgeToken = await deployContract(
ERC677BridgeToken,
[BRIDGEABLE_TOKEN_NAME, BRIDGEABLE_TOKEN_SYMBOL, BRIDGEABLE_TOKEN_DECIMALS],
{ from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce }
)
foreignNonce++
console.log('[Foreign] BRIDGEABLE_TOKEN_SYMBOL: ', erc677bridgeToken.options.address)
console.log('deploying storage for foreign validators')
const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
const storageValidatorsForeign = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] BridgeValidators Storage: ', storageValidatorsForeign.options.address)
console.log('\ndeploying implementation for foreign validators')
let bridgeValidatorsForeign = await deployContract(BridgeValidators, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
console.log('[Foreign] BridgeValidators Implementation: ', bridgeValidatorsForeign.options.address)
const bridgeValidatorsForeign = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] BridgeValidators Implementation: ',
bridgeValidatorsForeign.options.address
)
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods.upgradeTo('1', bridgeValidatorsForeign.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToBridgeVForeign = await sendRawTx({
const upgradeToBridgeVForeignData = await storageValidatorsForeign.methods
.upgradeTo('1', bridgeValidatorsForeign.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVForeign = await sendRawTxForeign({
data: upgradeToBridgeVForeignData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txUpgradeToBridgeVForeign.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txUpgradeToBridgeVForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge Validators with following parameters:\n')
console.log(`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`)
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsForeign.options.address = storageValidatorsForeign.options.address
const initializeForeignData = await bridgeValidatorsForeign.methods.initialize(
REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_OWNER_MULTISIG
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeForeign = await sendRawTx({
const initializeForeignData = await bridgeValidatorsForeign.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, FOREIGN_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeForeign = await sendRawTxForeign({
data: initializeForeignData,
nonce: foreignNonce,
to: bridgeValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txInitializeForeign.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txInitializeForeign.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\nTransferring ownership of ValidatorsProxy\n')
const validatorsForeignOwnershipData = await storageValidatorsForeign.methods.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txValidatorsForeignOwnershipData = await sendRawTx({
const validatorsForeignOwnershipData = await storageValidatorsForeign.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txValidatorsForeignOwnershipData = await sendRawTxForeign({
data: validatorsForeignOwnershipData,
nonce: foreignNonce,
to: storageValidatorsForeign.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txValidatorsForeignOwnershipData.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txValidatorsForeignOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ndeploying foreignBridge storage\n')
const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
const foreignBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log('[Foreign] ForeignBridge Storage: ', foreignBridgeStorage.options.address)
console.log('\ndeploying foreignBridge implementation\n')
const foreignBridgeImplementation = await deployContract(ForeignBridge, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, network: 'foreign', nonce: foreignNonce})
foreignNonce++;
console.log('[Foreign] ForeignBridge Implementation: ', foreignBridgeImplementation.options.address)
const foreignBridgeImplementation = await deployContract(ForeignBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'foreign',
nonce: foreignNonce
})
foreignNonce++
console.log(
'[Foreign] ForeignBridge Implementation: ',
foreignBridgeImplementation.options.address
)
console.log('\nhooking up ForeignBridge storage to ForeignBridge implementation')
const upgradeToForeignBridgeData = await foreignBridgeStorage.methods.upgradeTo('1', foreignBridgeImplementation.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToForeignBridge = await sendRawTx({
const upgradeToForeignBridgeData = await foreignBridgeStorage.methods
.upgradeTo('1', foreignBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToForeignBridge = await sendRawTxForeign({
data: upgradeToForeignBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txUpgradeToForeignBridge.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txUpgradeToForeignBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\ninitializing Foreign Bridge with following parameters:\n')
console.log(`Foreign Validators: ${storageValidatorsForeign.options.address},
FOREIGN_DAILY_LIMIT : ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei(FOREIGN_DAILY_LIMIT)} in eth,
FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(FOREIGN_MAX_AMOUNT_PER_TX)} in eth,
FOREIGN_MIN_AMOUNT_PER_TX: ${FOREIGN_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(FOREIGN_MIN_AMOUNT_PER_TX)} in eth
FOREIGN_DAILY_LIMIT : ${FOREIGN_DAILY_LIMIT} which is ${Web3Utils.fromWei(
FOREIGN_DAILY_LIMIT
)} in eth,
FOREIGN_MAX_AMOUNT_PER_TX: ${FOREIGN_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
FOREIGN_MAX_AMOUNT_PER_TX
)} in eth,
FOREIGN_MIN_AMOUNT_PER_TX: ${FOREIGN_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
FOREIGN_MIN_AMOUNT_PER_TX
)} in eth
`)
foreignBridgeImplementation.options.address = foreignBridgeStorage.options.address
const initializeFBridgeData = await foreignBridgeImplementation.methods.initialize(
storageValidatorsForeign.options.address, erc677bridgeToken.options.address, FOREIGN_DAILY_LIMIT, FOREIGN_MAX_AMOUNT_PER_TX, FOREIGN_MIN_AMOUNT_PER_TX, FOREIGN_GAS_PRICE, FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeBridge = await sendRawTx({
const initializeFBridgeData = await foreignBridgeImplementation.methods
.initialize(
storageValidatorsForeign.options.address,
erc677bridgeToken.options.address,
FOREIGN_DAILY_LIMIT,
FOREIGN_MAX_AMOUNT_PER_TX,
FOREIGN_MIN_AMOUNT_PER_TX,
FOREIGN_GAS_PRICE,
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeBridge = await sendRawTxForeign({
data: initializeFBridgeData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txInitializeBridge.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txInitializeBridge.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('\nset bridge contract on ERC677BridgeToken')
const setBridgeContractData = await erc677bridgeToken.methods
.setBridgeContract(foreignBridgeStorage.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const setBridgeContract = await sendRawTxForeign({
data: setBridgeContractData,
nonce: foreignNonce,
to: erc677bridgeToken.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
})
assert.equal(setBridgeContract.status, '0x1', 'Transaction Failed')
foreignNonce++
console.log('transferring ownership of ERC677BridgeToken token to foreignBridge contract')
const txOwnershipData = await erc677bridgeToken.methods.transferOwnership(foreignBridgeStorage.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS})
const txOwnership = await sendRawTx({
const txOwnershipData = await erc677bridgeToken.methods
.transferOwnership(foreignBridgeStorage.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txOwnership = await sendRawTxForeign({
data: txOwnershipData,
nonce: foreignNonce,
to: erc677bridgeToken.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txOwnership.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txOwnership.status, '0x1', 'Transaction Failed')
foreignNonce++
const bridgeOwnershipData = await foreignBridgeStorage.methods.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txBridgeOwnershipData = await sendRawTx({
const bridgeOwnershipData = await foreignBridgeStorage.methods
.transferProxyOwnership(FOREIGN_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txBridgeOwnershipData = await sendRawTxForeign({
data: bridgeOwnershipData,
nonce: foreignNonce,
to: foreignBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: FOREIGN_RPC_URL
});
assert.equal(txBridgeOwnershipData.status, '0x1', 'Transaction Failed');
foreignNonce++;
})
assert.equal(txBridgeOwnershipData.status, '0x1', 'Transaction Failed')
foreignNonce++
return {
foreignBridge:
{
address: foreignBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(foreignBridgeStorage.deployedBlockNumber)
},
erc677: {address: erc677bridgeToken.options.address}
foreignBridge: {
address: foreignBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(foreignBridgeStorage.deployedBlockNumber)
},
erc677: { address: erc677bridgeToken.options.address }
}
}
module.exports = deployForeign;
module.exports = deployForeign

View File

@ -1,149 +1,175 @@
const assert = require('assert')
const Web3Utils = require('web3-utils')
require('dotenv').config({
path: __dirname + '../../.env'
});
const assert = require('assert');
const env = require('../loadEnv')
const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils')
const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3')
const {deployContract, privateKeyToAddress, sendRawTx} = require('../deploymentUtils');
const {web3Home, deploymentPrivateKey, HOME_RPC_URL} = require('../web3');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json');
const EternalStorageProxy = require('../../../build/contracts/EternalStorageProxy.json')
const BridgeValidators = require('../../../build/contracts/BridgeValidators.json')
const HomeBridge = require('../../../build/contracts/HomeBridgeNativeToErc.json')
const VALIDATORS = process.env.VALIDATORS.split(" ")
const HOME_GAS_PRICE = Web3Utils.toWei(process.env.HOME_GAS_PRICE, 'gwei');
const VALIDATORS = env.VALIDATORS.split(' ')
const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
REQUIRED_NUMBER_OF_VALIDATORS,
HOME_GAS_PRICE,
HOME_OWNER_MULTISIG,
HOME_UPGRADEABLE_ADMIN_VALIDATORS,
HOME_UPGRADEABLE_ADMIN_BRIDGE,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_REQUIRED_BLOCK_CONFIRMATIONS,
} = process.env;
HOME_REQUIRED_BLOCK_CONFIRMATIONS
} = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployHome()
{
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS);
async function deployHome() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('deploying storage for home validators')
const storageValidatorsHome = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
const storageValidatorsHome = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Storage: ', storageValidatorsHome.options.address)
homeNonce++;
homeNonce++
console.log('\ndeploying implementation for home validators')
let bridgeValidatorsHome = await deployContract(BridgeValidators, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
const bridgeValidatorsHome = await deployContract(BridgeValidators, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
console.log('[Home] BridgeValidators Implementation: ', bridgeValidatorsHome.options.address)
homeNonce++;
homeNonce++
console.log('\nhooking up eternal storage to BridgeValidators')
const upgradeToBridgeVHomeData = await storageValidatorsHome.methods.upgradeTo('1', bridgeValidatorsHome.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToBridgeVHome = await sendRawTx({
const upgradeToBridgeVHomeData = await storageValidatorsHome.methods
.upgradeTo('1', bridgeValidatorsHome.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToBridgeVHome = await sendRawTxHome({
data: upgradeToBridgeVHomeData,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToBridgeVHome.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txUpgradeToBridgeVHome.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge Validators with following parameters:\n')
console.log(`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`)
console.log(
`REQUIRED_NUMBER_OF_VALIDATORS: ${REQUIRED_NUMBER_OF_VALIDATORS}, VALIDATORS: ${VALIDATORS}`
)
bridgeValidatorsHome.options.address = storageValidatorsHome.options.address
const initializeData = await bridgeValidatorsHome.methods.initialize(
REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_OWNER_MULTISIG
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS})
const txInitialize = await sendRawTx({
const initializeData = await bridgeValidatorsHome.methods
.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, HOME_OWNER_MULTISIG)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitialize = await sendRawTxHome({
data: initializeData,
nonce: homeNonce,
to: bridgeValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txInitialize.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txInitialize.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Validators Proxy contract');
const proxyDataTransfer = await storageValidatorsHome.methods.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_VALIDATORS).encodeABI();
const txProxyDataTransfer = await sendRawTx({
console.log('transferring proxy ownership to multisig for Validators Proxy contract')
const proxyDataTransfer = await storageValidatorsHome.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_VALIDATORS)
.encodeABI()
const txProxyDataTransfer = await sendRawTxHome({
data: proxyDataTransfer,
nonce: homeNonce,
to: storageValidatorsHome.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txProxyDataTransfer.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txProxyDataTransfer.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ndeploying homeBridge storage\n')
const homeBridgeStorage = await deployContract(EternalStorageProxy, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
homeNonce++;
const homeBridgeStorage = await deployContract(EternalStorageProxy, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Storage: ', homeBridgeStorage.options.address)
console.log('\ndeploying homeBridge implementation\n')
const homeBridgeImplementation = await deployContract(HomeBridge, [], {from: DEPLOYMENT_ACCOUNT_ADDRESS, nonce: homeNonce})
homeNonce++;
const homeBridgeImplementation = await deployContract(HomeBridge, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce: homeNonce
})
homeNonce++
console.log('[Home] HomeBridge Implementation: ', homeBridgeImplementation.options.address)
console.log('\nhooking up HomeBridge storage to HomeBridge implementation')
const upgradeToHomeBridgeData = await homeBridgeStorage.methods.upgradeTo('1', homeBridgeImplementation.options.address)
.encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txUpgradeToHomeBridge = await sendRawTx({
const upgradeToHomeBridgeData = await homeBridgeStorage.methods
.upgradeTo('1', homeBridgeImplementation.options.address)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txUpgradeToHomeBridge = await sendRawTxHome({
data: upgradeToHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txUpgradeToHomeBridge.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txUpgradeToHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\ninitializing Home Bridge with following parameters:\n')
console.log(`Home Validators: ${storageValidatorsHome.options.address},
HOME_DAILY_LIMIT : ${HOME_DAILY_LIMIT} which is ${Web3Utils.fromWei(HOME_DAILY_LIMIT)} in eth,
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(HOME_MAX_AMOUNT_PER_TX)} in eth,
HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(HOME_MIN_AMOUNT_PER_TX)} in eth,
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MAX_AMOUNT_PER_TX
)} in eth,
HOME_MIN_AMOUNT_PER_TX: ${HOME_MIN_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(
HOME_MIN_AMOUNT_PER_TX
)} in eth,
HOME_GAS_PRICE: ${HOME_GAS_PRICE}, HOME_REQUIRED_BLOCK_CONFIRMATIONS : ${HOME_REQUIRED_BLOCK_CONFIRMATIONS}
`)
homeBridgeImplementation.options.address = homeBridgeStorage.options.address
const initializeHomeBridgeData = await homeBridgeImplementation.methods.initialize(
storageValidatorsHome.options.address, HOME_DAILY_LIMIT, HOME_MAX_AMOUNT_PER_TX, HOME_MIN_AMOUNT_PER_TX, HOME_GAS_PRICE, HOME_REQUIRED_BLOCK_CONFIRMATIONS
).encodeABI({from: DEPLOYMENT_ACCOUNT_ADDRESS});
const txInitializeHomeBridge = await sendRawTx({
const initializeHomeBridgeData = await homeBridgeImplementation.methods
.initialize(
storageValidatorsHome.options.address,
HOME_DAILY_LIMIT,
HOME_MAX_AMOUNT_PER_TX,
HOME_MIN_AMOUNT_PER_TX,
HOME_GAS_PRICE,
HOME_REQUIRED_BLOCK_CONFIRMATIONS
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
const txInitializeHomeBridge = await sendRawTxHome({
data: initializeHomeBridgeData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
});
assert.equal(txInitializeHomeBridge.status, '0x1', 'Transaction Failed');
homeNonce++;
})
assert.equal(txInitializeHomeBridge.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('transferring proxy ownership to multisig for Home bridge Proxy contract');
const homeBridgeProxyData = await homeBridgeStorage.methods.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_BRIDGE).encodeABI();
const txhomeBridgeProxyData = await sendRawTx({
console.log('transferring proxy ownership to multisig for Home bridge Proxy contract')
const homeBridgeProxyData = await homeBridgeStorage.methods
.transferProxyOwnership(HOME_UPGRADEABLE_ADMIN_BRIDGE)
.encodeABI()
const txhomeBridgeProxyData = await sendRawTxHome({
data: homeBridgeProxyData,
nonce: homeNonce,
to: homeBridgeStorage.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL
})
assert.equal(txhomeBridgeProxyData.status, '0x1', 'Transaction Failed');
homeNonce++;
assert.equal(txhomeBridgeProxyData.status, '0x1', 'Transaction Failed')
homeNonce++
console.log('\nHome Deployment Bridge is complete\n')
return {
address: homeBridgeStorage.options.address,
deployedBlockNumber: Web3Utils.hexToNumber(homeBridgeStorage.deployedBlockNumber)
}
}
module.exports = deployHome;
module.exports = deployHome

View File

@ -0,0 +1,33 @@
const Web3Utils = require('web3-utils')
const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3')
const { deployContract, privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils')
const BlockReward = require('../../../build/contracts/BlockReward.json')
const env = require('../loadEnv')
const { DEPLOYMENT_ACCOUNT_PRIVATE_KEY } = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function deployBlockReward() {
let homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
const blockReward = await deployContract(BlockReward, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
network: 'home',
nonce: homeNonce
})
homeNonce++
const blockRewardAddress = blockReward.options.address
await sendRawTxHome({
to: blockRewardAddress,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL,
value: Web3Utils.toHex(Web3Utils.toWei('1000')),
nonce: homeNonce
})
console.log(blockRewardAddress)
}
deployBlockReward().catch(console.error)

View File

@ -0,0 +1,28 @@
const { web3Home, deploymentPrivateKey, HOME_RPC_URL } = require('../web3')
const { privateKeyToAddress, sendRawTxHome } = require('../deploymentUtils')
const HomeBridge = require('../../../build/contracts/HomeBridgeErcToNative.json')
const env = require('../loadEnv')
const { BLOCK_REWARD_ADDRESS, DEPLOYMENT_ACCOUNT_PRIVATE_KEY, HOME_BRIDGE_ADDRESS } = env
const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVATE_KEY)
async function setBlockReward() {
const homeNonce = await web3Home.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
const homeBridge = new web3Home.eth.Contract(HomeBridge.abi, HOME_BRIDGE_ADDRESS)
const setBlockRewardAddressData = await homeBridge.methods
.setBlockRewardContract(BLOCK_REWARD_ADDRESS)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
await sendRawTxHome({
data: setBlockRewardAddressData,
to: homeBridge.options.address,
privateKey: deploymentPrivateKey,
url: HOME_RPC_URL,
nonce: homeNonce
})
}
setBlockReward().catch(console.error)

View File

@ -1,25 +1,24 @@
require('dotenv').config({
path: __dirname + '/../.env'
});
const Web3Utils = require('web3-utils');
const Web3 = require('web3')
const env = require('./loadEnv')
const HOME_RPC_URL = process.env.HOME_RPC_URL;
const FOREIGN_RPC_URL = process.env.FOREIGN_RPC_URL;
const Web3 = require('web3');
const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL);
const web3Home = new Web3(homeProvider);
const {
HOME_RPC_URL,
FOREIGN_RPC_URL,
GET_RECEIPT_INTERVAL_IN_MILLISECONDS,
DEPLOYMENT_ACCOUNT_PRIVATE_KEY
} = env
const foreignProvider = new Web3.providers.HttpProvider(FOREIGN_RPC_URL);
const web3Foreign = new Web3(foreignProvider);
const homeProvider = new Web3.providers.HttpProvider(HOME_RPC_URL)
const web3Home = new Web3(homeProvider)
const GAS_PRICE = Web3Utils.toWei(process.env.DEPLOYMENT_GAS_PRICE, 'gwei');
const GAS_LIMIT = process.env.DEPLOYMENT_GAS_LIMIT;
const GET_RECEIPT_INTERVAL_IN_MILLISECONDS = process.env.GET_RECEIPT_INTERVAL_IN_MILLISECONDS;
const foreignProvider = new Web3.providers.HttpProvider(FOREIGN_RPC_URL)
const web3Foreign = new Web3(foreignProvider)
const { HOME_DEPLOYMENT_GAS_PRICE, FOREIGN_DEPLOYMENT_GAS_PRICE } = env
const GAS_LIMIT = env.DEPLOYMENT_GAS_LIMIT
const DEPLOYMENT_ACCOUNT_PRIVATE_KEY = process.env.DEPLOYMENT_ACCOUNT_PRIVATE_KEY;
const deploymentPrivateKey = Buffer.from(DEPLOYMENT_ACCOUNT_PRIVATE_KEY, 'hex')
module.exports = {
web3Home,
web3Foreign,
@ -27,6 +26,7 @@ module.exports = {
HOME_RPC_URL,
FOREIGN_RPC_URL,
GAS_LIMIT,
GAS_PRICE,
HOME_DEPLOYMENT_GAS_PRICE,
FOREIGN_DEPLOYMENT_GAS_PRICE,
GET_RECEIPT_INTERVAL_IN_MILLISECONDS
}

View File

@ -4,10 +4,11 @@ const BridgeValidators = artifacts.require("BridgeValidators.sol");
const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol");
const ERC677BridgeToken = artifacts.require("ERC677BridgeToken.sol");
const {ERROR_MSG, ZERO_ADDRESS} = require('../setup');
const {ERROR_MSG, ZERO_ADDRESS, INVALID_ARGUMENTS} = require('../setup');
const {createMessage, sign, signatureToVRS} = require('../helpers/helpers');
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
const requireBlockConfirmations = 8;
const gasPrice = web3.toWei('1', 'gwei')
contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
let validatorContract, authorities, owner, token;
@ -28,7 +29,15 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
'0'.should.be.bignumber.equal(await foreignBridge.deployedAtBlock())
false.should.be.equal(await foreignBridge.isInitialized())
'0'.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations())
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations).should.be.rejectedWith(INVALID_ARGUMENTS);
await foreignBridge.initialize(ZERO_ADDRESS, token.address, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, 0, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, 0).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
token.address.should.be.equal(await foreignBridge.erc20token());
true.should.be.equal(await foreignBridge.isInitialized())
@ -36,6 +45,8 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
token.address.should.be.equal(await foreignBridge.erc20token());
(await foreignBridge.deployedAtBlock()).should.be.bignumber.above(0);
requireBlockConfirmations.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations())
const contractGasPrice = await foreignBridge.gasPrice()
contractGasPrice.should.be.bignumber.equal(gasPrice)
const bridgeMode = '0xba4690f5' // 4 bytes of keccak256('erc-to-erc-core')
const mode = await foreignBridge.getBridgeMode();
mode.should.be.equal(bridgeMode)
@ -50,7 +61,7 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
beforeEach(async () => {
foreignBridge = await ForeignBridge.new()
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
await token.mint(foreignBridge.address,value);
})
it('should allow to executeSignatures', async () => {
@ -134,7 +145,7 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract})
foreignBridgeWithMultiSignatures = await ForeignBridge.new()
const oneEther = web3.toBigNumber(web3.toWei(1, "ether"));
await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, {from: ownerOfValidatorContract});
await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, {from: ownerOfValidatorContract});
await token.mint(foreignBridgeWithMultiSignatures.address,value);
})
it('withdraw should fail if not enough signatures are provided', async () => {
@ -191,7 +202,7 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled;
foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address);
await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations)
await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice)
// Deploy V2
let foreignImplV2 = await ForeignBridgeV2.new();
@ -211,7 +222,7 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
let storageProxy = await EternalStorageProxy.new().should.be.fulfilled;
let foreignBridge = await ForeignBridge.new();
let data = foreignBridge.initialize.request(
fakeValidatorsAddress, fakeTokenAddress, requireBlockConfirmations).params[0].data
fakeValidatorsAddress, fakeTokenAddress, requireBlockConfirmations, gasPrice).params[0].data
await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled;
let finalContract = await ForeignBridge.at(storageProxy.address);
true.should.be.equal(await finalContract.isInitialized());
@ -224,7 +235,7 @@ contract('ForeignBridge_ERC20_to_ERC20', async (accounts) => {
const owner = accounts[0];
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
foreignBridge = await ForeignBridge.new();
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
let tokenSecond = await ERC677BridgeToken.new("Roman Token", "RST", 18);

View File

@ -0,0 +1,264 @@
const ForeignBridge = artifacts.require("ForeignBridgeErcToNative.sol");
const ForeignBridgeV2 = artifacts.require("ForeignBridgeV2.sol");
const BridgeValidators = artifacts.require("BridgeValidators.sol");
const EternalStorageProxy = artifacts.require("EternalStorageProxy.sol");
const ERC677BridgeToken = artifacts.require("ERC677BridgeToken.sol");
const { ERROR_MSG, ZERO_ADDRESS } = require('../setup');
const { createMessage, sign, signatureToVRS } = require('../helpers/helpers');
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
const requireBlockConfirmations = 8;
const gasPrice = web3.toWei('1', 'gwei');
contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
let validatorContract, authorities, owner, token;
before(async () => {
validatorContract = await BridgeValidators.new()
authorities = [accounts[1], accounts[2]];
owner = accounts[0]
await validatorContract.initialize(1, authorities, owner)
})
describe('#initialize', async () => {
it('should initialize', async () => {
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
let foreignBridge = await ForeignBridge.new();
ZERO_ADDRESS.should.be.equal(await foreignBridge.erc20token());
ZERO_ADDRESS.should.be.equal(await foreignBridge.validatorContract())
'0'.should.be.bignumber.equal(await foreignBridge.deployedAtBlock())
false.should.be.equal(await foreignBridge.isInitialized())
'0'.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations())
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
token.address.should.be.equal(await foreignBridge.erc20token());
true.should.be.equal(await foreignBridge.isInitialized())
validatorContract.address.should.be.equal(await foreignBridge.validatorContract());
token.address.should.be.equal(await foreignBridge.erc20token());
(await foreignBridge.deployedAtBlock()).should.be.bignumber.above(0);
requireBlockConfirmations.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations())
const contractGasPrice = await foreignBridge.gasPrice()
contractGasPrice.should.be.bignumber.equal(gasPrice)
const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-erc-core')
const mode = await foreignBridge.getBridgeMode();
mode.should.be.equal(bridgeMode)
const [major, minor, patch] = await foreignBridge.getBridgeInterfacesVersion()
major.should.be.bignumber.gte(0)
minor.should.be.bignumber.gte(0)
patch.should.be.bignumber.gte(0)
})
})
describe('#executeSignatures', async () => {
const value = web3.toBigNumber(web3.toWei(0.25, "ether"));
let foreignBridge
beforeEach(async () => {
foreignBridge = await ForeignBridge.new()
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
await token.mint(foreignBridge.address,value);
})
it('should allow to executeSignatures', async () => {
const recipientAccount = accounts[3];
const balanceBefore = await token.balanceOf(recipientAccount)
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address);
const signature = await sign(authorities[0], message)
const vrs = signatureToVRS(signature);
false.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
const { logs } = await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled
logs[0].event.should.be.equal("RelayedMessage")
logs[0].args.recipient.should.be.equal(recipientAccount)
logs[0].args.value.should.be.bignumber.equal(value)
const balanceAfter = await token.balanceOf(recipientAccount);
const balanceAfterBridge = await token.balanceOf(foreignBridge.address);
balanceAfter.should.be.bignumber.equal(balanceBefore.add(value))
balanceAfterBridge.should.be.bignumber.equal(0)
true.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
})
it('should allow second withdrawal with different transactionHash but same recipient and value', async ()=> {
const recipientAccount = accounts[3];
const balanceBefore = await token.balanceOf(recipientAccount)
// tx 1
const value = web3.toBigNumber(web3.toWei(0.25, "ether"));
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address);
const signature = await sign(authorities[0], message)
const vrs = signatureToVRS(signature);
false.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled
// tx 2
await token.mint(foreignBridge.address,value);
var transactionHash2 = "0x77a496628a776a03d58d7e6059a5937f04bebd8ba4ff89f76dd4bb8ba7e291ee";
var message2 = createMessage(recipientAccount, value, transactionHash2, foreignBridge.address);
var signature2 = await sign(authorities[0], message2)
var vrs2 = signatureToVRS(signature2);
false.should.be.equal(await foreignBridge.relayedMessages(transactionHash2))
const {logs} = await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled
logs[0].event.should.be.equal("RelayedMessage")
logs[0].args.recipient.should.be.equal(recipientAccount)
logs[0].args.value.should.be.bignumber.equal(value)
const balanceAfter = await token.balanceOf(recipientAccount)
balanceAfter.should.be.bignumber.equal(balanceBefore.add(value.mul(2)))
true.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
true.should.be.equal(await foreignBridge.relayedMessages(transactionHash2))
})
it('should not allow second withdraw (replay attack) with same transactionHash but different recipient', async () => {
const recipientAccount = accounts[3];
// tx 1
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, value, transactionHash, foreignBridge.address);
const signature = await sign(authorities[0], message)
const vrs = signatureToVRS(signature);
false.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled
// tx 2
await token.mint(foreignBridge.address,value);
const message2 = createMessage(accounts[4], value, transactionHash, foreignBridge.address);
const signature2 = await sign(authorities[0], message2)
const vrs2 = signatureToVRS(signature2);
true.should.be.equal(await foreignBridge.relayedMessages(transactionHash))
await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.rejectedWith(ERROR_MSG)
})
})
describe('#withdraw with 2 minimum signatures', async () => {
let multisigValidatorContract, twoAuthorities, ownerOfValidatorContract, foreignBridgeWithMultiSignatures
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
beforeEach(async () => {
multisigValidatorContract = await BridgeValidators.new()
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
twoAuthorities = [accounts[0], accounts[1]];
ownerOfValidatorContract = accounts[3]
await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract})
foreignBridgeWithMultiSignatures = await ForeignBridge.new()
await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, {from: ownerOfValidatorContract});
await token.mint(foreignBridgeWithMultiSignatures.address,value);
})
it('withdraw should fail if not enough signatures are provided', async () => {
const recipientAccount = accounts[4];
// msg 1
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address);
const signature = await sign(twoAuthorities[0], message)
const vrs = signatureToVRS(signature);
false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash))
await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG)
// msg 2
const signature2 = await sign(twoAuthorities[1], message)
const vrs2 = signatureToVRS(signature2);
const {logs} = await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs2.v], [vrs.r, vrs2.r], [vrs.s, vrs2.s], message).should.be.fulfilled;
logs[0].event.should.be.equal("RelayedMessage")
logs[0].args.recipient.should.be.equal(recipientAccount)
logs[0].args.value.should.be.bignumber.equal(value)
true.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash))
})
it('withdraw should fail if duplicate signature is provided', async () => {
const recipientAccount = accounts[4];
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, value, transactionHash, foreignBridgeWithMultiSignatures.address);
const signature = await sign(twoAuthorities[0], message)
const vrs = signatureToVRS(signature);
false.should.be.equal(await foreignBridgeWithMultiSignatures.relayedMessages(transactionHash))
await foreignBridgeWithMultiSignatures.executeSignatures([vrs.v, vrs.v], [vrs.r, vrs.r], [vrs.s, vrs.s], message).should.be.rejectedWith(ERROR_MSG)
})
})
describe('#upgradeable', async () => {
it('can be upgraded', async () => {
const REQUIRED_NUMBER_OF_VALIDATORS = 1
const VALIDATORS = [accounts[1]]
const PROXY_OWNER = accounts[0]
// Validators Contract
let validatorsProxy = await EternalStorageProxy.new().should.be.fulfilled;
const validatorsContractImpl = await BridgeValidators.new().should.be.fulfilled;
await validatorsProxy.upgradeTo('1', validatorsContractImpl.address).should.be.fulfilled;
validatorsContractImpl.address.should.be.equal(await validatorsProxy.implementation())
validatorsProxy = await BridgeValidators.at(validatorsProxy.address);
await validatorsProxy.initialize(REQUIRED_NUMBER_OF_VALIDATORS, VALIDATORS, PROXY_OWNER).should.be.fulfilled;
let token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
// ForeignBridge V1 Contract
let foreignBridgeProxy = await EternalStorageProxy.new().should.be.fulfilled;
const foreignBridgeImpl = await ForeignBridge.new().should.be.fulfilled;
await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled;
foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address);
await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice)
// Deploy V2
let foreignImplV2 = await ForeignBridgeV2.new();
let foreignBridgeProxyUpgrade = await EternalStorageProxy.at(foreignBridgeProxy.address);
await foreignBridgeProxyUpgrade.upgradeTo('2', foreignImplV2.address).should.be.fulfilled;
foreignImplV2.address.should.be.equal(await foreignBridgeProxyUpgrade.implementation())
let foreignBridgeV2Proxy = await ForeignBridgeV2.at(foreignBridgeProxy.address)
await foreignBridgeV2Proxy.doSomething(accounts[2], {from: accounts[4]}).should.be.rejectedWith(ERROR_MSG)
await foreignBridgeV2Proxy.doSomething(accounts[2], {from: PROXY_OWNER}).should.be.fulfilled;
(await foreignBridgeV2Proxy.something()).should.be.equal(accounts[2])
})
it('can be deployed via upgradeToAndCall', async () => {
const fakeTokenAddress = accounts[7]
const fakeValidatorsAddress = accounts[6]
const storageProxy = await EternalStorageProxy.new().should.be.fulfilled;
const foreignBridge = await ForeignBridge.new();
const data = foreignBridge.initialize.request(fakeValidatorsAddress, fakeTokenAddress, requireBlockConfirmations, gasPrice).params[0].data
await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled;
let finalContract = await ForeignBridge.at(storageProxy.address);
true.should.be.equal(await finalContract.isInitialized());
fakeValidatorsAddress.should.be.equal(await finalContract.validatorContract())
})
})
describe('#claimTokens', async () => {
it('can send erc20', async () => {
const owner = accounts[0];
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
const foreignBridge = await ForeignBridge.new();
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
const tokenSecond = await ERC677BridgeToken.new("Roman Token", "RST", 18);
await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled;
halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0]))
await tokenSecond.transfer(foreignBridge.address, halfEther);
'0'.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[0]))
halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address))
await foreignBridge.claimTokens(tokenSecond.address, accounts[3], {from: owner});
'0'.should.be.bignumber.equal(await tokenSecond.balanceOf(foreignBridge.address))
halfEther.should.be.bignumber.equal(await tokenSecond.balanceOf(accounts[3]))
})
})
})

View File

@ -0,0 +1,454 @@
const Web3Utils = require('web3-utils')
const HomeBridge = artifacts.require('HomeBridgeErcToNative.sol')
const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol')
const BridgeValidators = artifacts.require('BridgeValidators.sol')
const BlockReward = artifacts.require('BlockReward')
const {ERROR_MSG, ZERO_ADDRESS} = require('../setup');
const {createMessage, sign } = require('../helpers/helpers');
const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether"));
const requireBlockConfirmations = 8;
const gasPrice = Web3Utils.toWei('1', 'gwei');
const oneEther = web3.toBigNumber(web3.toWei(1, "ether"));
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
contract('HomeBridge_ERC20_to_Native', async (accounts) => {
let homeContract, validatorContract, blockRewardContract, authorities, owner;
before(async () => {
validatorContract = await BridgeValidators.new()
blockRewardContract = await BlockReward.new()
authorities = [accounts[1]]
owner = accounts[0]
await validatorContract.initialize(1, authorities, owner)
})
describe('#initialize', async() => {
beforeEach(async () => {
homeContract = await HomeBridge.new()
})
it('sets variables', async () => {
ZERO_ADDRESS.should.be.equal(await homeContract.validatorContract())
'0'.should.be.bignumber.equal(await homeContract.deployedAtBlock())
'0'.should.be.bignumber.equal(await homeContract.dailyLimit())
'0'.should.be.bignumber.equal(await homeContract.maxPerTx())
false.should.be.equal(await homeContract.isInitialized())
ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract())
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.fulfilled
true.should.be.equal(await homeContract.isInitialized())
validatorContract.address.should.be.equal(await homeContract.validatorContract())
blockRewardContract.address.should.be.equal(await homeContract.blockRewardContract());
(await homeContract.deployedAtBlock()).should.be.bignumber.above(0)
'3'.should.be.bignumber.equal(await homeContract.dailyLimit())
'2'.should.be.bignumber.equal(await homeContract.maxPerTx())
'1'.should.be.bignumber.equal(await homeContract.minPerTx())
const contractGasPrice = await homeContract.gasPrice()
contractGasPrice.should.be.bignumber.equal(gasPrice)
const bridgeMode = '0x18762d46' // 4 bytes of keccak256('erc-to-native-core')
const mode = await homeContract.getBridgeMode();
mode.should.be.equal(bridgeMode)
const [major, minor, patch] = await homeContract.getBridgeInterfacesVersion()
major.should.be.bignumber.gte(0)
minor.should.be.bignumber.gte(0)
patch.should.be.bignumber.gte(0)
})
it('can update block reward contract', async () => {
ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract())
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.fulfilled
blockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
const secondBlockRewardContract = await BlockReward.new()
await homeContract.setBlockRewardContract(secondBlockRewardContract.address)
secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
const thirdBlockRewardContract = await BlockReward.new()
await homeContract.setBlockRewardContract(thirdBlockRewardContract.address, {from: accounts[4]}).should.be.rejectedWith(ERROR_MSG)
secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
const notAContract = accounts[5]
await homeContract.setBlockRewardContract(notAContract).should.be.rejectedWith(ERROR_MSG)
secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
await homeContract.setBlockRewardContract(validatorContract.address).should.be.rejectedWith(ERROR_MSG)
secondBlockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
})
it('cant set maxPerTx > dailyLimit', async () => {
false.should.be.equal(await homeContract.isInitialized())
await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG)
await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG)
false.should.be.equal(await homeContract.isInitialized())
})
it('can be deployed via upgradeToAndCall', async () => {
let storageProxy = await EternalStorageProxy.new().should.be.fulfilled;
let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, blockRewardContract.address).params[0].data
await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled
let finalContract = await HomeBridge.at(storageProxy.address);
true.should.be.equal(await finalContract.isInitialized())
validatorContract.address.should.be.equal(await finalContract.validatorContract())
blockRewardContract.address.should.be.equal(await finalContract.blockRewardContract())
"3".should.be.bignumber.equal(await finalContract.dailyLimit())
"2".should.be.bignumber.equal(await finalContract.maxPerTx())
"1".should.be.bignumber.equal(await finalContract.minPerTx())
})
})
describe('#fallback', async () => {
beforeEach(async () => {
homeContract = await HomeBridge.new()
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address)
})
it('should accept native coins', async () => {
const currentDay = await homeContract.getCurrentDay()
'0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address)
const minted = await blockRewardContract.mintedTotallyByBridge(homeContract.address)
minted.should.be.bignumber.equal(10)
const {logs} = await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
logs[0].event.should.be.equal('UserRequestForSignature')
logs[0].args.should.be.deep.equal({ recipient: accounts[1], value: new web3.BigNumber(1) })
'1'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
'1'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
const homeContractBalance = await web3.eth.getBalance(homeContract.address)
homeContractBalance.should.be.bignumber.equal('0')
})
it('should accumulate burnt coins', async () => {
await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address)
const currentDay = await homeContract.getCurrentDay()
'0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
'1'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
'2'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
'3'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
const homeContractBalance = await web3.eth.getBalance(homeContract.address)
homeContractBalance.should.be.bignumber.equal('0')
})
it('doesnt let you send more than daily limit', async () => {
await blockRewardContract.addMintedTotallyByBridge(10, homeContract.address)
const currentDay = await homeContract.getCurrentDay()
'0'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
'1'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
'1'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled;
'2'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.rejectedWith(ERROR_MSG);
await homeContract.setDailyLimit(4).should.be.fulfilled;
await homeContract.sendTransaction({ from: accounts[1], value: 2 }).should.be.fulfilled;
'4'.should.be.bignumber.equal(await homeContract.totalSpentPerDay(currentDay))
'4'.should.be.bignumber.equal(await homeContract.totalBurntCoins())
})
it('doesnt let you send more than max amount per tx', async () => {
await blockRewardContract.addMintedTotallyByBridge(200, homeContract.address)
await homeContract.sendTransaction({
from: accounts[1],
value: 1
}).should.be.fulfilled
await homeContract.sendTransaction({
from: accounts[1],
value: 3
}).should.be.rejectedWith(ERROR_MSG)
await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG);
await homeContract.setDailyLimit(100).should.be.fulfilled;
await homeContract.setMaxPerTx(99).should.be.fulfilled;
//meets max per tx and daily limit
await homeContract.sendTransaction({
from: accounts[1],
value: 99
}).should.be.fulfilled
//above daily limit
await homeContract.sendTransaction({
from: accounts[1],
value: 1
}).should.be.rejectedWith(ERROR_MSG)
})
it('should not let to deposit less than minPerTx', async () => {
const newDailyLimit = 100;
const newMaxPerTx = 50;
const newMinPerTx = 20;
await blockRewardContract.addMintedTotallyByBridge(200, homeContract.address)
await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled;
await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled;
await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled;
await homeContract.sendTransaction({ from: accounts[1], value: newMinPerTx }).should.be.fulfilled
await homeContract.sendTransaction({ from: accounts[1], value: newMinPerTx - 1 }).should.be.rejectedWith(ERROR_MSG)
})
it('should fail if not enough bridged tokens', async () => {
const initiallyMinted = await blockRewardContract.mintedTotallyByBridge(homeContract.address)
initiallyMinted.should.be.bignumber.equal(0)
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.rejectedWith(ERROR_MSG)
await blockRewardContract.addMintedTotallyByBridge(2, homeContract.address)
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.fulfilled
await homeContract.sendTransaction({ from: accounts[1], value: 1 }).should.be.rejectedWith(ERROR_MSG)
const minted = await blockRewardContract.mintedTotallyByBridge(homeContract.address)
const burnt = await homeContract.totalBurntCoins()
minted.should.be.bignumber.equal(2)
burnt.should.be.bignumber.equal(2)
})
})
describe('#setting limits', async () => {
let homeContract;
beforeEach(async () => {
homeContract = await HomeBridge.new()
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address)
})
it('setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => {
await homeContract.setMaxPerTx(2, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG);
await homeContract.setMaxPerTx(2, {from: owner}).should.be.fulfilled;
await homeContract.setMaxPerTx(3, {from: owner}).should.be.rejectedWith(ERROR_MSG);
})
it('setMinPerTx allows to set only to owner and cannot be more than daily limit and should be less than maxPerTx', async () => {
await homeContract.setMinPerTx(1, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG);
await homeContract.setMinPerTx(1, {from: owner}).should.be.fulfilled;
await homeContract.setMinPerTx(2, {from: owner}).should.be.rejectedWith(ERROR_MSG);
})
})
describe('#executeAffirmation', async () => {
let homeBridge;
beforeEach(async () => {
homeBridge = await HomeBridge.new();
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await blockRewardContract.sendTransaction({
from: accounts[2],
value: oneEther
}).should.be.fulfilled
})
it('should allow validator to executeAffirmation', async () => {
const recipient = accounts[5];
const value = halfEther;
const balanceBefore = await web3.eth.getBalance(recipient)
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]})
logs[0].event.should.be.equal("SignedForAffirmation");
logs[0].args.should.be.deep.equal({
signer: authorities[0],
transactionHash
});
logs[1].event.should.be.equal("AffirmationCompleted");
logs[1].args.should.be.deep.equal({
recipient,
value,
transactionHash
})
const balanceAfter = await web3.eth.getBalance(recipient)
balanceAfter.should.be.bignumber.equal(balanceBefore.add(value))
const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash);
const senderHash = Web3Utils.soliditySha3(authorities[0], msgHash)
true.should.be.equal(await homeBridge.affirmationsSigned(senderHash))
})
it('test with 2 signatures required', async () => {
const validatorContractWith2Signatures = await BridgeValidators.new()
const authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]];
const ownerOfValidators = accounts[0]
await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators)
const homeBridgeWithTwoSigs = await HomeBridge.new();
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
const recipient = accounts[5];
const value = halfEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
const balanceBefore = await web3.eth.getBalance(recipient)
const msgHash = Web3Utils.soliditySha3(recipient, value, transactionHash);
const { logs } = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.fulfilled;
logs[0].event.should.be.equal("SignedForAffirmation");
logs[0].args.should.be.deep.equal({ signer: authorities[0], transactionHash });
const notProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash);
notProcessed.should.be.bignumber.equal(1);
await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG);
const secondSignature = await homeBridgeWithTwoSigs.executeAffirmation(recipient, value, transactionHash, {from: authoritiesTwoAccs[1]}).should.be.fulfilled;
const balanceAfter = await web3.eth.getBalance(recipient)
balanceAfter.should.be.bignumber.equal(balanceBefore.add(value))
secondSignature.logs[1].event.should.be.equal("AffirmationCompleted");
secondSignature.logs[1].args.should.be.deep.equal({ recipient, value, transactionHash })
const senderHash = Web3Utils.soliditySha3(authoritiesTwoAccs[0], msgHash)
true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash))
const senderHash2 = Web3Utils.soliditySha3(authoritiesTwoAccs[1], msgHash);
true.should.be.equal(await homeBridgeWithTwoSigs.affirmationsSigned(senderHash2))
const markedAsProcessed = await homeBridgeWithTwoSigs.numAffirmationsSigned(msgHash);
const processed = new web3.BigNumber(2).pow(255).add(2);
markedAsProcessed.should.be.bignumber.equal(processed)
})
it('should not allow non-validator to execute affirmation', async () => {
const recipient = accounts[5];
const value = oneEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: accounts[7]}).should.be.rejectedWith(ERROR_MSG);
})
it('should fail if the block reward contract is not set', async () => {
homeBridge = await HomeBridge.new();
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, ZERO_ADDRESS);
const recipient = accounts[5];
const value = halfEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG)
})
})
describe('#submitSignature', async () => {
let validatorContractWith2Signatures,authoritiesTwoAccs,ownerOfValidators,homeBridgeWithTwoSigs
beforeEach(async () => {
validatorContractWith2Signatures = await BridgeValidators.new()
authoritiesTwoAccs = [accounts[1], accounts[2], accounts[3]];
ownerOfValidators = accounts[0]
await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators)
homeBridgeWithTwoSigs = await HomeBridge.new();
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
})
it('allows a validator to submit a signature', async () => {
const recipientAccount = accounts[8]
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address);
const signature = await sign(authoritiesTwoAccs[0], message)
const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authorities[0]}).should.be.fulfilled;
logs[0].event.should.be.equal('SignedForUserRequest')
const { messageHash } = logs[0].args
const signatureFromContract = await homeBridgeWithTwoSigs.signature(messageHash, 0);
const messageFromContract = await homeBridgeWithTwoSigs.message(messageHash);
signature.should.be.equal(signatureFromContract);
messageFromContract.should.be.equal(messageFromContract);
const hashMsg = Web3Utils.soliditySha3(message);
const hashSenderMsg = Web3Utils.soliditySha3(authorities[0], hashMsg)
true.should.be.equal(await homeBridgeWithTwoSigs.messagesSigned(hashSenderMsg));
})
it('when enough requiredSignatures are collected, CollectedSignatures event is emitted', async () => {
const recipientAccount = accounts[8]
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address);
const signature = await sign(authoritiesTwoAccs[0], message)
const signature2 = await sign(authoritiesTwoAccs[1], message)
'2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures());
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled;
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG);
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG);
const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled;
logs.length.should.be.equal(2)
logs[1].event.should.be.equal('CollectedSignatures')
logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1])
})
it('attack when increasing requiredSignatures', async () => {
const recipientAccount = accounts[8]
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address);
const signature = await sign(authoritiesTwoAccs[0], message)
const signature2 = await sign(authoritiesTwoAccs[1], message)
const signature3 = await sign(authoritiesTwoAccs[2], message)
'2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures());
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled;
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.rejectedWith(ERROR_MSG);
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[1]}).should.be.rejectedWith(ERROR_MSG);
const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled;
logs.length.should.be.equal(2)
logs[1].event.should.be.equal('CollectedSignatures')
logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1])
await validatorContractWith2Signatures.setRequiredSignatures(3).should.be.fulfilled;
'3'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures());
await homeBridgeWithTwoSigs.submitSignature(signature3, message, {from: authoritiesTwoAccs[2]}).should.be.rejectedWith(ERROR_MSG);
})
it('attack when decreasing requiredSignatures', async () => {
const recipientAccount = accounts[8]
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";
const message = createMessage(recipientAccount, value, transactionHash, homeBridgeWithTwoSigs.address);
const signature = await sign(authoritiesTwoAccs[0], message)
const signature2 = await sign(authoritiesTwoAccs[1], message)
'2'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures());
await homeBridgeWithTwoSigs.submitSignature(signature, message, {from: authoritiesTwoAccs[0]}).should.be.fulfilled;
await validatorContractWith2Signatures.setRequiredSignatures(1).should.be.fulfilled;
'1'.should.be.bignumber.equal(await validatorContractWith2Signatures.requiredSignatures());
const { logs } = await homeBridgeWithTwoSigs.submitSignature(signature2, message, {from: authoritiesTwoAccs[1]}).should.be.fulfilled;
logs.length.should.be.equal(2)
logs[1].event.should.be.equal('CollectedSignatures')
logs[1].args.authorityResponsibleForRelay.should.be.equal(authoritiesTwoAccs[1])
})
})
describe('#requiredMessageLength', async () => {
beforeEach(async () => {
homeContract = await HomeBridge.new()
})
it('should return the required message length', async () => {
const requiredMessageLength = await homeContract.requiredMessageLength()
'104'.should.be.bignumber.equal(requiredMessageLength)
})
})
})

View File

@ -1,6 +1,15 @@
const POA20 = artifacts.require("ERC677BridgeToken.sol");
const ERC677ReceiverTest = artifacts.require("ERC677ReceiverTest.sol")
const {ERROR_MSG} = require('./setup');
const { ERROR_MSG, ZERO_ADDRESS} = require('./setup');
const Web3Utils = require('web3-utils');
const HomeErcToErcBridge = artifacts.require("HomeBridgeErcToErc.sol");
const ForeignNativeToErcBridge = artifacts.require("ForeignBridgeNativeToErc.sol");
const BridgeValidators = artifacts.require("BridgeValidators.sol");
const minPerTx = web3.toBigNumber(web3.toWei(0.01, "ether"));
const requireBlockConfirmations = 8;
const gasPrice = Web3Utils.toWei('1', 'gwei');
const oneEther = web3.toBigNumber(web3.toWei(1, "ether"));
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
contract('ERC677BridgeToken', async (accounts) => {
let token
@ -31,6 +40,40 @@ contract('ERC677BridgeToken', async (accounts) => {
minor.should.be.bignumber.gte(0)
patch.should.be.bignumber.gte(0)
})
describe('#bridgeContract', async() => {
it('can set bridge contract', async () => {
const homeErcToErcContract = await HomeErcToErcBridge.new();
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address);
})
it('only owner can set bridge contract', async () => {
const homeErcToErcContract = await HomeErcToErcBridge.new();
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
await token.setBridgeContract(homeErcToErcContract.address, {from: user }).should.be.rejectedWith(ERROR_MSG);
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
await token.setBridgeContract(homeErcToErcContract.address, {from: owner }).should.be.fulfilled;
(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address);
})
it('fail to set invalid bridge contract address', async () => {
const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b';
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
await token.setBridgeContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG);
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
await token.setBridgeContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG);
(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS);
})
})
describe('#mint', async() => {
it('can mint by owner', async () => {
(await token.totalSupply()).should.be.bignumber.equal(0);
@ -52,6 +95,16 @@ contract('ERC677BridgeToken', async (accounts) => {
})
describe('#transfer', async() => {
let homeErcToErcContract, foreignNativeToErcBridge, validatorContract
beforeEach(async () => {
validatorContract = await BridgeValidators.new()
const authorities = [accounts[2]];
await validatorContract.initialize(1, authorities, owner)
homeErcToErcContract = await HomeErcToErcBridge.new()
await homeErcToErcContract.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address)
foreignNativeToErcBridge = await ForeignNativeToErcBridge.new()
await foreignNativeToErcBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations);
})
it('sends tokens to recipient', async () => {
await token.mint(user, 1, {from: owner }).should.be.fulfilled;
await token.transfer(user, 1, {from: owner}).should.be.rejectedWith(ERROR_MSG);
@ -65,6 +118,58 @@ contract('ERC677BridgeToken', async (accounts) => {
value: new web3.BigNumber(1)
})
})
it('sends tokens to bridge contract', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
const result = await token.transfer(homeErcToErcContract.address, minPerTx, {from: user}).should.be.fulfilled;
result.logs[0].event.should.be.equal("Transfer")
result.logs[0].args.should.be.deep.equal({
from: user,
to: homeErcToErcContract.address,
value: minPerTx
})
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled;
const result2 = await token.transfer(foreignNativeToErcBridge.address, minPerTx, {from: user}).should.be.fulfilled;
result2.logs[0].event.should.be.equal("Transfer")
result2.logs[0].args.should.be.deep.equal({
from: user,
to: foreignNativeToErcBridge.address,
value: minPerTx
})
})
it('sends tokens to contract that does not contains onTokenTransfer method', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
const result = await token.transfer(validatorContract.address, minPerTx, {from: user}).should.be.fulfilled;
result.logs[0].event.should.be.equal("Transfer")
result.logs[0].args.should.be.deep.equal({
from: user,
to: validatorContract.address,
value: minPerTx
})
result.logs[1].event.should.be.equal("ContractFallbackCallFailed")
result.logs[1].args.should.be.deep.equal({
from: user,
to: validatorContract.address,
value: minPerTx
})
})
it('fail to send tokens to bridge contract out of limits', async () => {
const lessThanMin = web3.toBigNumber(web3.toWei(0.0001, "ether"))
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.transfer(homeErcToErcContract.address, lessThanMin, {from: user}).should.be.rejectedWith(ERROR_MSG);
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled;
await token.transfer(foreignNativeToErcBridge.address, lessThanMin, {from: user}).should.be.rejectedWith(ERROR_MSG);
})
})
describe("#burn", async () => {
@ -78,6 +183,16 @@ contract('ERC677BridgeToken', async (accounts) => {
})
describe('#transferAndCall', () => {
let homeErcToErcContract, foreignNativeToErcBridge, validatorContract
beforeEach(async () => {
validatorContract = await BridgeValidators.new()
const authorities = [accounts[2]];
await validatorContract.initialize(1, authorities, owner)
homeErcToErcContract = await HomeErcToErcBridge.new()
await homeErcToErcContract.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, token.address)
foreignNativeToErcBridge = await ForeignNativeToErcBridge.new()
await foreignNativeToErcBridge.initialize(validatorContract.address, token.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations);
})
it('calls contractFallback', async () => {
const receiver = await ERC677ReceiverTest.new();
(await receiver.from()).should.be.equal('0x0000000000000000000000000000000000000000');
@ -100,6 +215,46 @@ contract('ERC677BridgeToken', async (accounts) => {
(await receiver.data()).should.be.equal(callDoSomething123);
(await receiver.someVar()).should.be.bignumber.equal('123');
})
it('sends tokens to bridge contract', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
const result = await token.transferAndCall(homeErcToErcContract.address, minPerTx, '0x', {from: user}).should.be.fulfilled;
result.logs[0].event.should.be.equal("Transfer")
result.logs[0].args.should.be.deep.equal({
from: user,
to: homeErcToErcContract.address,
value: minPerTx
})
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled;
const result2 = await token.transferAndCall(foreignNativeToErcBridge.address, minPerTx, '0x', {from: user}).should.be.fulfilled;
result2.logs[0].event.should.be.equal("Transfer")
result2.logs[0].args.should.be.deep.equal({
from: user,
to: foreignNativeToErcBridge.address,
value: minPerTx
})
})
it('fail to sends tokens to contract that does not contains onTokenTransfer method', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
await token.transferAndCall(validatorContract.address, minPerTx, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG);
})
it('fail to send tokens to bridge contract out of limits', async () => {
const lessThanMin = web3.toBigNumber(web3.toWei(0.0001, "ether"))
await token.mint(user, web3.toWei(1, "ether"), {from: owner }).should.be.fulfilled;
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled;
await token.transferAndCall(homeErcToErcContract.address, lessThanMin, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG);
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled;
await token.transferAndCall(foreignNativeToErcBridge.address, lessThanMin, '0x', {from: user}).should.be.rejectedWith(ERROR_MSG);
})
})
describe('#claimtokens', async () => {
it('can take send ERC20 tokens', async ()=> {

View File

@ -8,3 +8,4 @@ require('chai')
exports.ERROR_MSG = 'VM Exception while processing transaction: revert';
exports.ERROR_MSG_OPCODE = 'VM Exception while processing transaction: invalid opcode';
exports.ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
exports.INVALID_ARGUMENTS = 'Invalid number of arguments to Solidity function'