Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ apidoc/
node_modules

artifacts/
hardhat.config.js
truffle-config.js
migrations/
document/
go_abi/
cache/
13 changes: 13 additions & 0 deletions contracts/core/assets/LPToken_template/LPToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pragma solidity ^0.5.0;

import "./../../../libs/GSN/Context.sol";
import "./../../../libs/token/ERC20/ERC20.sol";
import "./../../../libs/token/ERC20/ERC20Detailed.sol";

contract LPToken is Context, ERC20, ERC20Detailed {

constructor(string memory name, string memory symbol, uint8 decimal, address initReceiver, uint initAmount)
public ERC20Detailed(name, symbol, decimal) {
_mint(initReceiver, initAmount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pragma solidity ^0.5.0;

interface IEventWitness {
event EventWitnessed(address indexed sender, bytes32 indexed hash);
function witness(bytes calldata evt) external ;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import "./../upgrade/UpgradableECCM.sol";
import "./../libs/EthCrossChainUtils.sol";
import "./../interface/IEthCrossChainManager.sol";
import "./../interface/IEthCrossChainData.sol";
import "./../interface/IEventWitness.sol";
contract EthCrossChainManager is IEthCrossChainManager, UpgradableECCM {
using SafeMath for uint256;

address constant EVENT_WITNESS = ; // add mainnet witness address here
address public whiteLister;
mapping(address => bool) public whiteListFromContract;
mapping(address => mapping(bytes => bool)) public whiteListContractMethodMap;
Expand Down Expand Up @@ -177,6 +179,10 @@ contract EthCrossChainManager is IEthCrossChainManager, UpgradableECCM {

// Fire the cross chain event denoting there is a cross chain request from Ethereum network to other public chains through Poly chain network
emit CrossChainEvent(tx.origin, paramTxHash, msg.sender, toChainId, toContract, rawParam);

// call EventWitness for ont-evm
IEventWitness(EVENT_WITNESS).witness(rawParam);

return true;
}
/* @notice Verify Poly chain header and proof, execute the cross chain tx from Poly chain to Ethereum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
pragma solidity ^0.5.16;

import "./../../../libs/math/SafeMath.sol";
import "./../../../libs/common/ZeroCopySource.sol";
import "./../../../libs/common/ZeroCopySink.sol";
import "./../../../libs/utils/Utils.sol";
import "./../upgrade/UpgradableECCM.sol";
import "./../libs/EthCrossChainUtils.sol";
import "./../interface/IEthCrossChainManager.sol";
import "./../interface/IEthCrossChainData.sol";
import "./../interface/IEventWitness.sol";
contract EthCrossChainManagerForTest is IEthCrossChainManager, UpgradableECCM {
using SafeMath for uint256;

address constant EVENT_WITNESS = 0x2b1143484bf5097A29678FD9592f75FE4639CA08;
event InitGenesisBlockEvent(uint256 height, bytes rawHeader);
event ChangeBookKeeperEvent(uint256 height, bytes rawHeader);
event CrossChainEvent(address indexed sender, bytes txId, address proxyOrAssetContract, uint64 toChainId, bytes toContract, bytes rawdata);
event VerifyHeaderAndExecuteTxEvent(uint64 fromChainID, bytes toContract, bytes crossChainTxHash, bytes fromChainTxHash);
constructor(
address _eccd,
uint64 _chainId
) UpgradableECCM(_eccd,_chainId) public {}

/* @notice sync Poly chain genesis block header to smart contrat
* @dev this function can only be called once, nextbookkeeper of rawHeader can't be empty
* @param rawHeader Poly chain genesis block raw header or raw Header including switching consensus peers info
* @return true or false
*/
function initGenesisBlock(bytes memory rawHeader, bytes memory pubKeyList) whenNotPaused public returns(bool) {
// Load Ethereum cross chain data contract
IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);

// Make sure the contract has not been initialized before
require(eccd.getCurEpochConPubKeyBytes().length == 0, "EthCrossChainData contract has already been initialized!");

// Parse header and convit the public keys into nextBookKeeper and compare it with header.nextBookKeeper to verify the validity of signature
ECCUtils.Header memory header = ECCUtils.deserializeHeader(rawHeader);
(bytes20 nextBookKeeper, address[] memory keepers) = ECCUtils.verifyPubkey(pubKeyList);
require(header.nextBookkeeper == nextBookKeeper, "NextBookers illegal");

// Record current epoch start height and public keys (by storing them in address format)
require(eccd.putCurEpochStartHeight(header.height), "Save Poly chain current epoch start height to Data contract failed!");
require(eccd.putCurEpochConPubKeyBytes(ECCUtils.serializeKeepers(keepers)), "Save Poly chain current epoch book keepers to Data contract failed!");

// Fire the event
emit InitGenesisBlockEvent(header.height, rawHeader);
return true;
}

/* @notice change Poly chain consensus book keeper
* @param rawHeader Poly chain change book keeper block raw header
* @param pubKeyList Poly chain consensus nodes public key list
* @param sigList Poly chain consensus nodes signature list
* @return true or false
*/
function changeBookKeeper(bytes memory rawHeader, bytes memory pubKeyList, bytes memory sigList) whenNotPaused public returns(bool) {
// Load Ethereum cross chain data contract
ECCUtils.Header memory header = ECCUtils.deserializeHeader(rawHeader);
IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);

// Make sure rawHeader.height is higher than recorded current epoch start height
uint64 curEpochStartHeight = eccd.getCurEpochStartHeight();
require(header.height > curEpochStartHeight, "The height of header is lower than current epoch start height!");

// Ensure the rawHeader is the key header including info of switching consensus peers by containing non-empty nextBookKeeper field
require(header.nextBookkeeper != bytes20(0), "The nextBookKeeper of header is empty");

// Verify signature of rawHeader comes from pubKeyList
address[] memory polyChainBKs = ECCUtils.deserializeKeepers(eccd.getCurEpochConPubKeyBytes());
uint n = polyChainBKs.length;
require(ECCUtils.verifySig(rawHeader, sigList, polyChainBKs, n - (n - 1) / 3), "Verify signature failed!");

// Convert pubKeyList into ethereum address format and make sure the compound address from the converted ethereum addresses
// equals passed in header.nextBooker
(bytes20 nextBookKeeper, address[] memory keepers) = ECCUtils.verifyPubkey(pubKeyList);
require(header.nextBookkeeper == nextBookKeeper, "NextBookers illegal");

// update current epoch start height of Poly chain and current epoch consensus peers book keepers addresses
require(eccd.putCurEpochStartHeight(header.height), "Save MC LatestHeight to Data contract failed!");
require(eccd.putCurEpochConPubKeyBytes(ECCUtils.serializeKeepers(keepers)), "Save Poly chain book keepers bytes to Data contract failed!");

// Fire the change book keeper event
emit ChangeBookKeeperEvent(header.height, rawHeader);
return true;
}


/* @notice ERC20 token cross chain to other blockchain.
* this function push tx event to blockchain
* @param toChainId Target chain id
* @param toContract Target smart contract address in target block chain
* @param txData Transaction data for target chain, include to_address, amount
* @return true or false
*/
function crossChain(uint64 toChainId, bytes calldata toContract, bytes calldata method, bytes calldata txData) whenNotPaused external returns (bool) {

// Load Ethereum cross chain data contract
IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);

// To help differentiate two txs, the ethTxHashIndex is increasing automatically
uint256 txHashIndex = eccd.getEthTxHashIndex();

// Convert the uint256 into bytes
bytes memory paramTxHash = Utils.uint256ToBytes(txHashIndex);

// Construct the makeTxParam, and put the hash info storage, to help provide proof of tx existence
bytes memory rawParam = abi.encodePacked(ZeroCopySink.WriteVarBytes(paramTxHash),
ZeroCopySink.WriteVarBytes(abi.encodePacked(sha256(abi.encodePacked(address(this), paramTxHash)))),
ZeroCopySink.WriteVarBytes(Utils.addressToBytes(msg.sender)),
ZeroCopySink.WriteUint64(toChainId),
ZeroCopySink.WriteVarBytes(toContract),
ZeroCopySink.WriteVarBytes(method),
ZeroCopySink.WriteVarBytes(txData)
);

// Must save it in the storage to be included in the proof to be verified.
require(eccd.putEthTxHash(keccak256(rawParam)), "Save ethTxHash by index to Data contract failed!");

// Fire the cross chain event denoting there is a cross chain request from Ethereum network to other public chains through Poly chain network
emit CrossChainEvent(tx.origin, paramTxHash, msg.sender, toChainId, toContract, rawParam);

// call EventWitness for ont-evm
IEventWitness(EVENT_WITNESS).witness(rawParam);

return true;
}
/* @notice Verify Poly chain header and proof, execute the cross chain tx from Poly chain to Ethereum
* @param proof Poly chain tx merkle proof
* @param rawHeader The header containing crossStateRoot to verify the above tx merkle proof
* @param headerProof The header merkle proof used to verify rawHeader
* @param curRawHeader Any header in current epoch consensus of Poly chain
* @param headerSig The coverted signature veriable for solidity derived from Poly chain consensus nodes' signature
* used to verify the validity of curRawHeader
* @return true or false
*/
function verifyHeaderAndExecuteTx(bytes memory proof, bytes memory rawHeader, bytes memory headerProof, bytes memory curRawHeader,bytes memory headerSig) whenNotPaused public returns (bool){
ECCUtils.Header memory header = ECCUtils.deserializeHeader(rawHeader);
// Load ehereum cross chain data contract
IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);

// Get stored consensus public key bytes of current poly chain epoch and deserialize Poly chain consensus public key bytes to address[]
address[] memory polyChainBKs = ECCUtils.deserializeKeepers(eccd.getCurEpochConPubKeyBytes());

uint256 curEpochStartHeight = eccd.getCurEpochStartHeight();

uint n = polyChainBKs.length;
if (header.height >= curEpochStartHeight) {
// It's enough to verify rawHeader signature
require(ECCUtils.verifySig(rawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify poly chain header signature failed!");
} else {
// We need to verify the signature of curHeader
require(ECCUtils.verifySig(curRawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify poly chain current epoch header signature failed!");

// Then use curHeader.StateRoot and headerProof to verify rawHeader.CrossStateRoot
ECCUtils.Header memory curHeader = ECCUtils.deserializeHeader(curRawHeader);
bytes memory proveValue = ECCUtils.merkleProve(headerProof, curHeader.blockRoot);
require(ECCUtils.getHeaderHash(rawHeader) == Utils.bytesToBytes32(proveValue), "verify header proof failed!");
}

// Through rawHeader.CrossStatesRoot, the toMerkleValue or cross chain msg can be verified and parsed from proof
bytes memory toMerkleValueBs = ECCUtils.merkleProve(proof, header.crossStatesRoot);

// Parse the toMerkleValue struct and make sure the tx has not been processed, then mark this tx as processed
ECCUtils.ToMerkleValue memory toMerkleValue = ECCUtils.deserializeMerkleValue(toMerkleValueBs);
require(!eccd.checkIfFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "the transaction has been executed!");
require(eccd.markFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "Save crosschain tx exist failed!");

// Ethereum ChainId is 2, we need to check the transaction is for Ethereum network
require(toMerkleValue.makeTxParam.toChainId == chainId, "This Tx is not aiming at this network!");

// Obtain the targeting contract, so that Ethereum cross chain manager contract can trigger the executation of cross chain tx on Ethereum side
address toContract = Utils.bytesToAddress(toMerkleValue.makeTxParam.toContract);
require(toContract != EthCrossChainDataAddress, "No eccd here!");

//TODO: check this part to make sure we commit the next line when doing local net UT test
require(_executeCrossChainTx(toContract, toMerkleValue.makeTxParam.method, toMerkleValue.makeTxParam.args, toMerkleValue.makeTxParam.fromContract, toMerkleValue.fromChainID), "Execute CrossChain Tx failed!");

// Fire the cross chain event denoting the executation of cross chain tx is successful,
// and this tx is coming from other public chains to current Ethereum network
emit VerifyHeaderAndExecuteTxEvent(toMerkleValue.fromChainID, toMerkleValue.makeTxParam.toContract, toMerkleValue.txHash, toMerkleValue.makeTxParam.txHash);

return true;
}

/* @notice Dynamically invoke the targeting contract, and trigger executation of cross chain tx on Ethereum side
* @param _toContract The targeting contract that will be invoked by the Ethereum Cross Chain Manager contract
* @param _method At which method will be invoked within the targeting contract
* @param _args The parameter that will be passed into the targeting contract
* @param _fromContractAddr From chain smart contract address
* @param _fromChainId Indicate from which chain current cross chain tx comes
* @return true or false
*/
function _executeCrossChainTx(address _toContract, bytes memory _method, bytes memory _args, bytes memory _fromContractAddr, uint64 _fromChainId) internal returns (bool){
// // Ensure the targeting contract gonna be invoked is indeed a contract rather than a normal account address
// require(Utils.isContract(_toContract), "The passed in address is not a contract!");
// bytes memory returnData;
// bool success;

// // The returnData will be bytes32, the last byte must be 01;
// (success, returnData) = _toContract.call(abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, "(bytes,bytes,uint64)"))), abi.encode(_args, _fromContractAddr, _fromChainId)));

// // Ensure the executation is successful
// require(success == true, "EthCrossChain call business contract failed");

// // Ensure the returned value is true
// require(returnData.length != 0, "No return value from business contract!");
// (bool res,) = ZeroCopySource.NextBool(returnData, 31);
// require(res == true, "EthCrossChain call business contract return is not true");

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import "./../upgrade/UpgradableECCM.sol";
import "./../libs/EthCrossChainUtils.sol";
import "./../interface/IEthCrossChainManager.sol";
import "./../interface/IEthCrossChainData.sol";
import "./../interface/IEventWitness.sol";
contract EthCrossChainManagerNoWhiteList is IEthCrossChainManager, UpgradableECCM {
using SafeMath for uint256;

address constant EVENT_WITNESS = 0xA8a1c2E2739725a14072B0bB1C6FAb0B36C15952; // testnet
event InitGenesisBlockEvent(uint256 height, bytes rawHeader);
event ChangeBookKeeperEvent(uint256 height, bytes rawHeader);
event CrossChainEvent(address indexed sender, bytes txId, address proxyOrAssetContract, uint64 toChainId, bytes toContract, bytes rawdata);
Expand Down Expand Up @@ -117,6 +119,10 @@ contract EthCrossChainManagerNoWhiteList is IEthCrossChainManager, UpgradableECC

// Fire the cross chain event denoting there is a cross chain request from Ethereum network to other public chains through Poly chain network
emit CrossChainEvent(tx.origin, paramTxHash, msg.sender, toChainId, toContract, rawParam);

// call EventWitness for ont-evm
IEventWitness(EVENT_WITNESS).witness(rawParam);

return true;
}
/* @notice Verify Poly chain header and proof, execute the cross chain tx from Poly chain to Ethereum
Expand Down
Loading