Merge branch 'develop' into fix-interface-version-#92
# Conflicts: # contracts/ERC677BridgeToken.sol # contracts/upgradeable_contracts/BasicBridge.sol
This commit is contained in:
commit
2465bc82f8
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
8.9
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
138
deploy/README.md
138
deploy/README.md
|
@ -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
|
||||
|
|
149
deploy/deploy.js
149
deploy/deploy.js
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
|
||||
module.exports = {
|
||||
ZERO_ADDRESS
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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]))
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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 ()=> {
|
||||
|
|
|
@ -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'
|
||||
|
|
Loading…
Reference in New Issue