ETH Price: $2,074.25 (-2.54%)

Transaction Decoder

Block:
14659598 at Apr-26-2022 10:21:31 AM +UTC
Transaction Fee:
0.005922748685158852 ETH $12.29
Gas Used:
214,811 Gas / 27.571905932 Gwei

Emitted Events:

643 DMOD.Transfer( from=0x250e76987d838a75310c34bf422ea9f1AC4Cc906, to=0xa787F09349999A61434cFB75118C6A9d0CAc9406, value=57609615858188949686659 )
644 0x250e76987d838a75310c34bf422ea9f1ac4cc906.0xd90288730b87c2b8e0c45bd82260fd22478aba30ae1c4d578b8daba9261604df( 0xd90288730b87c2b8e0c45bd82260fd22478aba30ae1c4d578b8daba9261604df, 0000000000000000000000005f6c5c2fb289db2228d159c69621215e354218d7, 000000000000000000000000a787f09349999a61434cfb75118c6a9d0cac9406, 000000000000000000000000000000000000000000000c3306064a324ee08983 )
645 EthCrossChainManager.VerifyHeaderAndExecuteTxEvent( fromChainID=6, toContract=0x250e76987d838a75310c34bf422ea9f1AC4Cc906, crossChainTxHash=0x8747284EF6342112A0ED1B128B3615094D13BD56631F536012C75040AF0DF253, fromChainTxHash=0x000000000000000000000000000000000000000000000000000000000002F04F )

Account State Difference:

  Address   Before After State Difference Code
0x5f6c5C2f...e354218d7
0x7a1979f8...2113B6Cd8
0.228127351798505174 Eth
Nonce: 11176
0.222204603113346322 Eth
Nonce: 11177
0.005922748685158852
0xcF2afe10...37fCb10f2
(Ethermine)
1,472.339643817562000061 Eth1,472.339858628562000061 Eth0.000214811

Execution Trace

EthCrossChainManager.verifyHeaderAndExecuteTx( proof=0xEF208747284EF6342112A0ED1B128B3615094D13BD56631F536012C75040AF0DF253060000000000000020000000000000000000000000000000000000000000000000000000000002F04F20967F3A77648218B8C5CFA85CEC94F0A9CE73211A6BAAB97675DA30C5CFE2EEE7142F7AC9436BA4B548F9582AF91CA1EF02CD2F1F03020000000000000014250E76987D838A75310C34BF422EA9F1AC4CC90606756E6C6F636B4A145F6C5C2FB289DB2228D159C69621215E354218D714A787F09349999A61434CFB75118C6A9D0CAC94068389E04E324A0606330C00000000000000000000000000000000000000000000, rawHeader=0x000000000000000000000000F650B36D619D05991236E3BBF5FC0DDF59ECF669A93E040B459602E4C04D5BEDB935C785D35578142BAA8B6DF5C250CF0066D057DCA5E6A5BF248638A4396D3FA9C70810505AEBCAECE6FBE401E082B48CCF133C69C14764A628E325ED7BF958A46D593F9D4AD42EE8B0A27603E494BFDBFB2790660A1B3D6B9DF716227CFB1937C5676250232201B6E1EF248C18415CFD13017B226C6561646572223A342C227672665F76616C7565223A2242414768596B6F51506773794776786F7470766C787344346B2B3962773257684E497873595A484D73442F505932654D71663156456C655639714E5A6E4B55464F76394F4B31735977794677327634554B484335454B303D222C227672665F70726F6F66223A226B3435476B4D6646496D674D6C614B765667767252554E5153587A4C7535345462777A44656563336F4A45397272687A3745306647677832396143766D6E7166523734794A63704B2B6E34556D442F507262683668673D3D222C226C6173745F636F6E6669675F626C6F636B5F6E756D223A31383936303030302C226E65775F636861696E5F636F6E666967223A6E756C6C7D0000000000000000000000000000000000000000, headerProof=0x, curRawHeader=0x, headerSig=0xFB1B999FDFE582119C5E7B47B625E233FC5BE5BDD49D5C921F8A1BE2E327414240E9601009C884DC88055668C49EFAC45B5A1A68A84A04DB31CFEBE16D2F077001B0E8A7F8EE76071800891F5B0AED4148CDC118534CB149A50A2D161336AACC946888AD663D91F5D2D7B7114B95379B7B4E96A95A0A0C0432C027A6EF87EA6E8D0055C748E5FA0772D7506A61AE942DDEB4120105D03D7B31911C01735A9F10E2EA16CDA56ED4C567CCEFB9BAE33604A50A6466B0BF2F94EF40E538879E0CCD32A000D05BADE9E8B3C3F7AFEAC9F2FB2D2AD0ACBAAB88345E12282CB8DC7BD820048C7BE0A2642F966DA617B451C3A72E1A42FFB9A4794E58028296AA650CF495CECF01 ) => ( True )
  • 0xcf2afe102057ba5c16f899271045a0a37fcb10f2.STATICCALL( )
  • 0xcf2afe102057ba5c16f899271045a0a37fcb10f2.STATICCALL( )
  • Null: 0x000...002.00000000( )
  • Null: 0x000...002.11bd1b5c( )
  • Null: 0x000...002.e15fc45d( )
  • Null: 0x000...001.fd846250( )
  • Null: 0x000...002.e15fc45d( )
  • Null: 0x000...001.fd846250( )
  • Null: 0x000...002.e15fc45d( )
  • Null: 0x000...001.fd846250( )
  • Null: 0x000...002.e15fc45d( )
  • Null: 0x000...001.fd846250( )
  • Null: 0x000...002.00208747( )
  • 0xcf2afe102057ba5c16f899271045a0a37fcb10f2.0586763c( )
  • 0xcf2afe102057ba5c16f899271045a0a37fcb10f2.e90bfdcf( )
  • 0x250e76987d838a75310c34bf422ea9f1ac4cc906.06af4b9f( )
    • 0x5a51e2ebf8d136926b9ca7b59b60464e7c44d2eb.STATICCALL( )
    • DMOD.transfer( recipient=0xa787F09349999A61434cFB75118C6A9d0CAc9406, amount=57609615858188949686659 ) => ( True )
      verifyHeaderAndExecuteTx[EthCrossChainManager (ln:1530)]
      File 1 of 2: EthCrossChainManager
      pragma solidity ^0.5.0;
      pragma experimental ABIEncoderV2;
      
      contract Context {
          // Empty internal constructor, to prevent people from mistakenly deploying
          // an instance of this contract, which should be used via inheritance.
          constructor () internal { }
          // solhint-disable-previous-line no-empty-blocks
      
          function _msgSender() internal view returns (address payable) {
              return msg.sender;
          }
      
          function _msgData() internal view returns (bytes memory) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
          }
      }
      
      contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor () internal {
              address msgSender = _msgSender();
              _owner = msgSender;
              emit OwnershipTransferred(address(0), msgSender);
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(isOwner(), "Ownable: caller is not the owner");
              _;
          }
      
          /**
           * @dev Returns true if the caller is the current owner.
           */
          function isOwner() public view returns (bool) {
              return _msgSender() == _owner;
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public  onlyOwner {
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           */
          function _transferOwnership(address newOwner) internal {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
      }
      
      contract Pausable is Context {
          /**
           * @dev Emitted when the pause is triggered by a pauser (`account`).
           */
          event Paused(address account);
      
          /**
           * @dev Emitted when the pause is lifted by a pauser (`account`).
           */
          event Unpaused(address account);
      
          bool private _paused;
      
          /**
           * @dev Initializes the contract in unpaused state.
           */
          constructor () internal {
              _paused = false;
          }
      
          /**
           * @dev Returns true if the contract is paused, and false otherwise.
           */
          function paused() public view returns (bool) {
              return _paused;
          }
      
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           */
          modifier whenNotPaused() {
              require(!_paused, "Pausable: paused");
              _;
          }
      
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           */
          modifier whenPaused() {
              require(_paused, "Pausable: not paused");
              _;
          }
      
          /**
           * @dev Called to pause, triggers stopped state.
           */
          function _pause() internal whenNotPaused {
              _paused = true;
              emit Paused(_msgSender());
          }
      
          /**
           * @dev Called to unpause, returns to normal state.
           */
          function _unpause() internal whenPaused {
              _paused = false;
              emit Unpaused(_msgSender());
          }
      }
      
      library ZeroCopySink {
          /* @notice          Convert boolean value into bytes
          *  @param b         The boolean value
          *  @return          Converted bytes array
          */
          function WriteBool(bool b) internal pure returns (bytes memory) {
              bytes memory buff;
              assembly{
                  buff := mload(0x40)
                  mstore(buff, 1)
                  switch iszero(b)
                  case 1 {
                      mstore(add(buff, 0x20), shl(248, 0x00))
                      // mstore8(add(buff, 0x20), 0x00)
                  }
                  default {
                      mstore(add(buff, 0x20), shl(248, 0x01))
                      // mstore8(add(buff, 0x20), 0x01)
                  }
                  mstore(0x40, add(buff, 0x21))
              }
              return buff;
          }
      
          /* @notice          Convert byte value into bytes
          *  @param b         The byte value
          *  @return          Converted bytes array
          */
          function WriteByte(byte b) internal pure returns (bytes memory) {
              return WriteUint8(uint8(b));
          }
      
          /* @notice          Convert uint8 value into bytes
          *  @param v         The uint8 value
          *  @return          Converted bytes array
          */
          function WriteUint8(uint8 v) internal pure returns (bytes memory) {
              bytes memory buff;
              assembly{
                  buff := mload(0x40)
                  mstore(buff, 1)
                  mstore(add(buff, 0x20), shl(248, v))
                  // mstore(add(buff, 0x20), byte(0x1f, v))
                  mstore(0x40, add(buff, 0x21))
              }
              return buff;
          }
      
          /* @notice          Convert uint16 value into bytes
          *  @param v         The uint16 value
          *  @return          Converted bytes array
          */
          function WriteUint16(uint16 v) internal pure returns (bytes memory) {
              bytes memory buff;
      
              assembly{
                  buff := mload(0x40)
                  let byteLen := 0x02
                  mstore(buff, byteLen)
                  for {
                      let mindex := 0x00
                      let vindex := 0x1f
                  } lt(mindex, byteLen) {
                      mindex := add(mindex, 0x01)
                      vindex := sub(vindex, 0x01)
                  }{
                      mstore8(add(add(buff, 0x20), mindex), byte(vindex, v))
                  }
                  mstore(0x40, add(buff, 0x22))
              }
              return buff;
          }
          
          /* @notice          Convert uint32 value into bytes
          *  @param v         The uint32 value
          *  @return          Converted bytes array
          */
          function WriteUint32(uint32 v) internal pure returns(bytes memory) {
              bytes memory buff;
              assembly{
                  buff := mload(0x40)
                  let byteLen := 0x04
                  mstore(buff, byteLen)
                  for {
                      let mindex := 0x00
                      let vindex := 0x1f
                  } lt(mindex, byteLen) {
                      mindex := add(mindex, 0x01)
                      vindex := sub(vindex, 0x01)
                  }{
                      mstore8(add(add(buff, 0x20), mindex), byte(vindex, v))
                  }
                  mstore(0x40, add(buff, 0x24))
              }
              return buff;
          }
      
          /* @notice          Convert uint64 value into bytes
          *  @param v         The uint64 value
          *  @return          Converted bytes array
          */
          function WriteUint64(uint64 v) internal pure returns(bytes memory) {
              bytes memory buff;
      
              assembly{
                  buff := mload(0x40)
                  let byteLen := 0x08
                  mstore(buff, byteLen)
                  for {
                      let mindex := 0x00
                      let vindex := 0x1f
                  } lt(mindex, byteLen) {
                      mindex := add(mindex, 0x01)
                      vindex := sub(vindex, 0x01)
                  }{
                      mstore8(add(add(buff, 0x20), mindex), byte(vindex, v))
                  }
                  mstore(0x40, add(buff, 0x28))
              }
              return buff;
          }
      
          /* @notice          Convert limited uint256 value into bytes
          *  @param v         The uint256 value
          *  @return          Converted bytes array
          */
          function WriteUint255(uint256 v) internal pure returns (bytes memory) {
              require(v <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds uint255 range");
              bytes memory buff;
      
              assembly{
                  buff := mload(0x40)
                  let byteLen := 0x20
                  mstore(buff, byteLen)
                  for {
                      let mindex := 0x00
                      let vindex := 0x1f
                  } lt(mindex, byteLen) {
                      mindex := add(mindex, 0x01)
                      vindex := sub(vindex, 0x01)
                  }{
                      mstore8(add(add(buff, 0x20), mindex), byte(vindex, v))
                  }
                  mstore(0x40, add(buff, 0x40))
              }
              return buff;
          }
      
          /* @notice          Encode bytes format data into bytes
          *  @param data      The bytes array data
          *  @return          Encoded bytes array
          */
          function WriteVarBytes(bytes memory data) internal pure returns (bytes memory) {
              uint64 l = uint64(data.length);
              return abi.encodePacked(WriteVarUint(l), data);
          }
      
          function WriteVarUint(uint64 v) internal pure returns (bytes memory) {
              if (v < 0xFD){
          		return WriteUint8(uint8(v));
          	} else if (v <= 0xFFFF) {
          		return abi.encodePacked(WriteByte(0xFD), WriteUint16(uint16(v)));
          	} else if (v <= 0xFFFFFFFF) {
                  return abi.encodePacked(WriteByte(0xFE), WriteUint32(uint32(v)));
          	} else {
          		return abi.encodePacked(WriteByte(0xFF), WriteUint64(uint64(v)));
          	}
          }
      }
      
      library ZeroCopySource {
          /* @notice              Read next byte as boolean type starting at offset from buff
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the boolean value
          *  @return              The the read boolean value and new offset
          */
          function NextBool(bytes memory buff, uint256 offset) internal pure returns(bool, uint256) {
              require(offset + 1 <= buff.length && offset < offset + 1, "Offset exceeds limit");
              // byte === bytes1
              byte v;
              assembly{
                  v := mload(add(add(buff, 0x20), offset))
              }
              bool value;
              if (v == 0x01) {
      		    value = true;
          	} else if (v == 0x00) {
                  value = false;
              } else {
                  revert("NextBool value error");
              }
              return (value, offset + 1);
          }
      
          /* @notice              Read next byte starting at offset from buff
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the byte value
          *  @return              The read byte value and new offset
          */
          function NextByte(bytes memory buff, uint256 offset) internal pure returns (byte, uint256) {
              require(offset + 1 <= buff.length && offset < offset + 1, "NextByte, Offset exceeds maximum");
              byte v;
              assembly{
                  v := mload(add(add(buff, 0x20), offset))
              }
              return (v, offset + 1);
          }
      
          /* @notice              Read next byte as uint8 starting at offset from buff
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the byte value
          *  @return              The read uint8 value and new offset
          */
          function NextUint8(bytes memory buff, uint256 offset) internal pure returns (uint8, uint256) {
              require(offset + 1 <= buff.length && offset < offset + 1, "NextUint8, Offset exceeds maximum");
              uint8 v;
              assembly{
                  let tmpbytes := mload(0x40)
                  let bvalue := mload(add(add(buff, 0x20), offset))
                  mstore8(tmpbytes, byte(0, bvalue))
                  mstore(0x40, add(tmpbytes, 0x01))
                  v := mload(sub(tmpbytes, 0x1f))
              }
              return (v, offset + 1);
          }
      
          /* @notice              Read next two bytes as uint16 type starting from offset
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the uint16 value
          *  @return              The read uint16 value and updated offset
          */
          function NextUint16(bytes memory buff, uint256 offset) internal pure returns (uint16, uint256) {
              require(offset + 2 <= buff.length && offset < offset + 2, "NextUint16, offset exceeds maximum");
              
              uint16 v;
              assembly {
                  let tmpbytes := mload(0x40)
                  let bvalue := mload(add(add(buff, 0x20), offset))
                  mstore8(tmpbytes, byte(0x01, bvalue))
                  mstore8(add(tmpbytes, 0x01), byte(0, bvalue))
                  mstore(0x40, add(tmpbytes, 0x02))
                  v := mload(sub(tmpbytes, 0x1e))
              }
              return (v, offset + 2);
          }
      
      
          /* @notice              Read next four bytes as uint32 type starting from offset
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the uint32 value
          *  @return              The read uint32 value and updated offset
          */
          function NextUint32(bytes memory buff, uint256 offset) internal pure returns (uint32, uint256) {
              require(offset + 4 <= buff.length && offset < offset + 4, "NextUint32, offset exceeds maximum");
              uint32 v;
              assembly {
                  let tmpbytes := mload(0x40)
                  let byteLen := 0x04
                  for {
                      let tindex := 0x00
                      let bindex := sub(byteLen, 0x01)
                      let bvalue := mload(add(add(buff, 0x20), offset))
                  } lt(tindex, byteLen) {
                      tindex := add(tindex, 0x01)
                      bindex := sub(bindex, 0x01)
                  }{
                      mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
                  }
                  mstore(0x40, add(tmpbytes, byteLen))
                  v := mload(sub(tmpbytes, sub(0x20, byteLen)))
              }
              return (v, offset + 4);
          }
      
          /* @notice              Read next eight bytes as uint64 type starting from offset
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the uint64 value
          *  @return              The read uint64 value and updated offset
          */
          function NextUint64(bytes memory buff, uint256 offset) internal pure returns (uint64, uint256) {
              require(offset + 8 <= buff.length && offset < offset + 8, "NextUint64, offset exceeds maximum");
              uint64 v;
              assembly {
                  let tmpbytes := mload(0x40)
                  let byteLen := 0x08
                  for {
                      let tindex := 0x00
                      let bindex := sub(byteLen, 0x01)
                      let bvalue := mload(add(add(buff, 0x20), offset))
                  } lt(tindex, byteLen) {
                      tindex := add(tindex, 0x01)
                      bindex := sub(bindex, 0x01)
                  }{
                      mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
                  }
                  mstore(0x40, add(tmpbytes, byteLen))
                  v := mload(sub(tmpbytes, sub(0x20, byteLen)))
              }
              return (v, offset + 8);
          }
      
          /* @notice              Read next 32 bytes as uint256 type starting from offset,
                                  there are limits considering the numerical limits in multi-chain
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the uint256 value
          *  @return              The read uint256 value and updated offset
          */
          function NextUint255(bytes memory buff, uint256 offset) internal pure returns (uint256, uint256) {
              require(offset + 32 <= buff.length && offset < offset + 32, "NextUint255, offset exceeds maximum");
              uint256 v;
              assembly {
                  let tmpbytes := mload(0x40)
                  let byteLen := 0x20
                  for {
                      let tindex := 0x00
                      let bindex := sub(byteLen, 0x01)
                      let bvalue := mload(add(add(buff, 0x20), offset))
                  } lt(tindex, byteLen) {
                      tindex := add(tindex, 0x01)
                      bindex := sub(bindex, 0x01)
                  }{
                      mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
                  }
                  mstore(0x40, add(tmpbytes, byteLen))
                  v := mload(tmpbytes)
              }
              require(v <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds the range");
              return (v, offset + 32);
          }
          /* @notice              Read next variable bytes starting from offset,
                                  the decoding rule coming from multi-chain
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the bytes value
          *  @return              The read variable bytes array value and updated offset
          */
          function NextVarBytes(bytes memory buff, uint256 offset) internal pure returns(bytes memory, uint256) {
              uint len;
              (len, offset) = NextVarUint(buff, offset);
              require(offset + len <= buff.length && offset < offset + len, "NextVarBytes, offset exceeds maximum");
              bytes memory tempBytes;
              assembly{
                  switch iszero(len)
                  case 0 {
                      // Get a location of some free memory and store it in tempBytes as
                      // Solidity does for memory variables.
                      tempBytes := mload(0x40)
      
                      // The first word of the slice result is potentially a partial
                      // word read from the original array. To read it, we calculate
                      // the length of that partial word and start copying that many
                      // bytes into the array. The first word we copy will start with
                      // data we don't care about, but the last `lengthmod` bytes will
                      // land at the beginning of the contents of the new array. When
                      // we're done copying, we overwrite the full first word with
                      // the actual length of the slice.
                      let lengthmod := and(len, 31)
      
                      // The multiplication in the next line is necessary
                      // because when slicing multiples of 32 bytes (lengthmod == 0)
                      // the following copy loop was copying the origin's length
                      // and then ending prematurely not copying everything it should.
                      let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                      let end := add(mc, len)
      
                      for {
                          // The multiplication in the next line has the same exact purpose
                          // as the one above.
                          let cc := add(add(add(buff, lengthmod), mul(0x20, iszero(lengthmod))), offset)
                      } lt(mc, end) {
                          mc := add(mc, 0x20)
                          cc := add(cc, 0x20)
                      } {
                          mstore(mc, mload(cc))
                      }
      
                      mstore(tempBytes, len)
      
                      //update free-memory pointer
                      //allocating the array padded to 32 bytes like the compiler does now
                      mstore(0x40, and(add(mc, 31), not(31)))
                  }
                  //if we want a zero-length slice let's just return a zero-length array
                  default {
                      tempBytes := mload(0x40)
      
                      mstore(0x40, add(tempBytes, 0x20))
                  }
              }
      
              return (tempBytes, offset + len);
          }
          /* @notice              Read next 32 bytes starting from offset,
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the bytes value
          *  @return              The read bytes32 value and updated offset
          */
          function NextHash(bytes memory buff, uint256 offset) internal pure returns (bytes32 , uint256) {
              require(offset + 32 <= buff.length && offset < offset + 32, "NextHash, offset exceeds maximum");
              bytes32 v;
              assembly {
                  v := mload(add(buff, add(offset, 0x20)))
              }
              return (v, offset + 32);
          }
      
          /* @notice              Read next 20 bytes starting from offset,
          *  @param buff          Source bytes array
          *  @param offset        The position from where we read the bytes value
          *  @return              The read bytes20 value and updated offset
          */
          function NextBytes20(bytes memory buff, uint256 offset) internal pure returns (bytes20 , uint256) {
              require(offset + 20 <= buff.length && offset < offset + 20, "NextBytes20, offset exceeds maximum");
              bytes20 v;
              assembly {
                  v := mload(add(buff, add(offset, 0x20)))
              }
              return (v, offset + 20);
          }
          
          function NextVarUint(bytes memory buff, uint256 offset) internal pure returns(uint, uint256) {
              byte v;
              (v, offset) = NextByte(buff, offset);
      
              uint value;
              if (v == 0xFD) {
                  // return NextUint16(buff, offset);
                  (value, offset) = NextUint16(buff, offset);
                  require(value >= 0xFD && value <= 0xFFFF, "NextUint16, value outside range");
                  return (value, offset);
              } else if (v == 0xFE) {
                  // return NextUint32(buff, offset);
                  (value, offset) = NextUint32(buff, offset);
                  require(value > 0xFFFF && value <= 0xFFFFFFFF, "NextVarUint, value outside range");
                  return (value, offset);
              } else if (v == 0xFF) {
                  // return NextUint64(buff, offset);
                  (value, offset) = NextUint64(buff, offset);
                  require(value > 0xFFFFFFFF, "NextVarUint, value outside range");
                  return (value, offset);
              } else{
                  // return (uint8(v), offset);
                  value = uint8(v);
                  require(value < 0xFD, "NextVarUint, value outside range");
                  return (value, offset);
              }
          }
      }
      
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           *
           * _Available since v2.4.0._
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) {
                  return 0;
              }
      
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           *
           * _Available since v2.4.0._
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              // Solidity only automatically asserts when dividing by 0
              require(b != 0, errorMessage);
              uint256 c = a / b;
              // assert(a == b * c + a % b); // There is no case in which this doesn't hold
      
              return c;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           *
           * _Available since v2.4.0._
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      
      library Utils {
      
          /* @notice      Convert the bytes array to bytes32 type, the bytes array length must be 32
          *  @param _bs   Source bytes array
          *  @return      bytes32
          */
          function bytesToBytes32(bytes memory _bs) internal pure returns (bytes32 value) {
              require(_bs.length == 32, "bytes length is not 32.");
              assembly {
                  // load 32 bytes from memory starting from position _bs + 0x20 since the first 0x20 bytes stores _bs length
                  value := mload(add(_bs, 0x20))
              }
          }
      
          /* @notice      Convert bytes to uint256
          *  @param _b    Source bytes should have length of 32
          *  @return      uint256
          */
          function bytesToUint256(bytes memory _bs) internal pure returns (uint256 value) {
              require(_bs.length == 32, "bytes length is not 32.");
              assembly {
                  // load 32 bytes from memory starting from position _bs + 32
                  value := mload(add(_bs, 0x20))
              }
              require(value <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds the range");
          }
      
          /* @notice      Convert uint256 to bytes
          *  @param _b    uint256 that needs to be converted
          *  @return      bytes
          */
          function uint256ToBytes(uint256 _value) internal pure returns (bytes memory bs) {
              require(_value <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds the range");
              assembly {
                  // Get a location of some free memory and store it in result as
                  // Solidity does for memory variables.
                  bs := mload(0x40)
                  // Put 0x20 at the first word, the length of bytes for uint256 value
                  mstore(bs, 0x20)
                  //In the next word, put value in bytes format to the next 32 bytes
                  mstore(add(bs, 0x20), _value)
                  // Update the free-memory pointer by padding our last write location to 32 bytes
                  mstore(0x40, add(bs, 0x40))
              }
          }
      
          /* @notice      Convert bytes to address
          *  @param _bs   Source bytes: bytes length must be 20
          *  @return      Converted address from source bytes
          */
          function bytesToAddress(bytes memory _bs) internal pure returns (address addr)
          {
              require(_bs.length == 20, "bytes length does not match address");
              assembly {
                  // for _bs, first word store _bs.length, second word store _bs.value
                  // load 32 bytes from mem[_bs+20], convert it into Uint160, meaning we take last 20 bytes as addr (address).
                  addr := mload(add(_bs, 0x14))
              }
      
          }
          
          /* @notice      Convert address to bytes
          *  @param _addr Address need to be converted
          *  @return      Converted bytes from address
          */
          function addressToBytes(address _addr) internal pure returns (bytes memory bs){
              assembly {
                  // Get a location of some free memory and store it in result as
                  // Solidity does for memory variables.
                  bs := mload(0x40)
                  // Put 20 (address byte length) at the first word, the length of bytes for uint256 value
                  mstore(bs, 0x14)
                  // logical shift left _a by 12 bytes, change _a from right-aligned to left-aligned
                  mstore(add(bs, 0x20), shl(96, _addr))
                  // Update the free-memory pointer by padding our last write location to 32 bytes
                  mstore(0x40, add(bs, 0x40))
             }
          }
      
          /* @notice          Do hash leaf as the multi-chain does
          *  @param _data     Data in bytes format
          *  @return          Hashed value in bytes32 format
          */
          function hashLeaf(bytes memory _data) internal pure returns (bytes32 result)  {
              result = sha256(abi.encodePacked(byte(0x0), _data));
          }
      
          /* @notice          Do hash children as the multi-chain does
          *  @param _l        Left node
          *  @param _r        Right node
          *  @return          Hashed value in bytes32 format
          */
          function hashChildren(bytes32 _l, bytes32  _r) internal pure returns (bytes32 result)  {
              result = sha256(abi.encodePacked(bytes1(0x01), _l, _r));
          }
      
          /* @notice              Compare if two bytes are equal, which are in storage and memory, seperately
                                  Refer from https://github.com/summa-tx/bitcoin-spv/blob/master/solidity/contracts/BytesLib.sol#L368
          *  @param _preBytes     The bytes stored in storage
          *  @param _postBytes    The bytes stored in memory
          *  @return              Bool type indicating if they are equal
          */
          function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
              bool success = true;
      
              assembly {
                  // we know _preBytes_offset is 0
                  let fslot := sload(_preBytes_slot)
                  // Arrays of 31 bytes or less have an even value in their slot,
                  // while longer arrays have an odd value. The actual length is
                  // the slot divided by two for odd values, and the lowest order
                  // byte divided by two for even values.
                  // If the slot is even, bitwise and the slot with 255 and divide by
                  // two to get the length. If the slot is odd, bitwise and the slot
                  // with -1 and divide by two.
                  let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
                  let mlength := mload(_postBytes)
      
                  // if lengths don't match the arrays are not equal
                  switch eq(slength, mlength)
                  case 1 {
                      // fslot can contain both the length and contents of the array
                      // if slength < 32 bytes so let's prepare for that
                      // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                      // slength != 0
                      if iszero(iszero(slength)) {
                          switch lt(slength, 32)
                          case 1 {
                              // blank the last byte which is the length
                              fslot := mul(div(fslot, 0x100), 0x100)
      
                              if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                                  // unsuccess:
                                  success := 0
                              }
                          }
                          default {
                              // cb is a circuit breaker in the for loop since there's
                              //  no said feature for inline assembly loops
                              // cb = 1 - don't breaker
                              // cb = 0 - break
                              let cb := 1
      
                              // get the keccak hash to get the contents of the array
                              mstore(0x0, _preBytes_slot)
                              let sc := keccak256(0x0, 0x20)
      
                              let mc := add(_postBytes, 0x20)
                              let end := add(mc, mlength)
      
                              // the next line is the loop condition:
                              // while(uint(mc < end) + cb == 2)
                              for {} eq(add(lt(mc, end), cb), 2) {
                                  sc := add(sc, 1)
                                  mc := add(mc, 0x20)
                              } {
                                  if iszero(eq(sload(sc), mload(mc))) {
                                      // unsuccess:
                                      success := 0
                                      cb := 0
                                  }
                              }
                          }
                      }
                  }
                  default {
                      // unsuccess:
                      success := 0
                  }
              }
      
              return success;
          }
      
          /* @notice              Slice the _bytes from _start index till the result has length of _length
                                  Refer from https://github.com/summa-tx/bitcoin-spv/blob/master/solidity/contracts/BytesLib.sol#L246
          *  @param _bytes        The original bytes needs to be sliced
          *  @param _start        The index of _bytes for the start of sliced bytes
          *  @param _length       The index of _bytes for the end of sliced bytes
          *  @return              The sliced bytes
          */
          function slice(
              bytes memory _bytes,
              uint _start,
              uint _length
          )
              internal
              pure
              returns (bytes memory)
          {
              require(_bytes.length >= (_start + _length));
      
              bytes memory tempBytes;
      
              assembly {
                  switch iszero(_length)
                  case 0 {
                      // Get a location of some free memory and store it in tempBytes as
                      // Solidity does for memory variables.
                      tempBytes := mload(0x40)
      
                      // The first word of the slice result is potentially a partial
                      // word read from the original array. To read it, we calculate
                      // the length of that partial word and start copying that many
                      // bytes into the array. The first word we copy will start with
                      // data we don't care about, but the last `lengthmod` bytes will
                      // land at the beginning of the contents of the new array. When
                      // we're done copying, we overwrite the full first word with
                      // the actual length of the slice.
                      // lengthmod <= _length % 32
                      let lengthmod := and(_length, 31)
      
                      // The multiplication in the next line is necessary
                      // because when slicing multiples of 32 bytes (lengthmod == 0)
                      // the following copy loop was copying the origin's length
                      // and then ending prematurely not copying everything it should.
                      let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                      let end := add(mc, _length)
      
                      for {
                          // The multiplication in the next line has the same exact purpose
                          // as the one above.
                          let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                      } lt(mc, end) {
                          mc := add(mc, 0x20)
                          cc := add(cc, 0x20)
                      } {
                          mstore(mc, mload(cc))
                      }
      
                      mstore(tempBytes, _length)
      
                      //update free-memory pointer
                      //allocating the array padded to 32 bytes like the compiler does now
                      mstore(0x40, and(add(mc, 31), not(31)))
                  }
                  //if we want a zero-length slice let's just return a zero-length array
                  default {
                      tempBytes := mload(0x40)
      
                      mstore(0x40, add(tempBytes, 0x20))
                  }
              }
      
              return tempBytes;
          }
          /* @notice              Check if the elements number of _signers within _keepers array is no less than _m
          *  @param _keepers      The array consists of serveral address
          *  @param _signers      Some specific addresses to be looked into
          *  @param _m            The number requirement paramter
          *  @return              True means containment, false meansdo do not contain.
          */
          function containMAddresses(address[] memory _keepers, address[] memory _signers, uint _m) internal pure returns (bool){
              uint m = 0;
              for(uint i = 0; i < _signers.length; i++){
                  for (uint j = 0; j < _keepers.length; j++) {
                      if (_signers[i] == _keepers[j]) {
                          m++;
                          delete _keepers[j];
                      }
                  }
              }
              return m >= _m;
          }
      
          /* @notice              TODO
          *  @param key
          *  @return
          */
          function compressMCPubKey(bytes memory key) internal pure returns (bytes memory newkey) {
               require(key.length >= 67, "key lenggh is too short");
               newkey = slice(key, 0, 35);
               if (uint8(key[66]) % 2 == 0){
                   newkey[2] = byte(0x02);
               } else {
                   newkey[2] = byte(0x03);
               }
               return newkey;
          }
          
          /**
           * @dev Returns true if `account` is a contract.
           *      Refer from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L18
           *
           * This test is non-exhaustive, and there may be false-negatives: during the
           * execution of a contract's constructor, its address will be reported as
           * not containing a contract.
           *
           * IMPORTANT: It is unsafe to assume that an address for which this
           * function returns false is an externally-owned account (EOA) and not a
           * contract.
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies in extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
      
              // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
              // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
              // for accounts without code, i.e. `keccak256('')`
              bytes32 codehash;
              bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
              // solhint-disable-next-line no-inline-assembly
              assembly { codehash := extcodehash(account) }
              return (codehash != 0x0 && codehash != accountHash);
          }
      }
      
      library ECCUtils {
          using SafeMath for uint256;
          
          struct Header {
              uint32 version;
              uint64 chainId;
              uint32 timestamp;
              uint32 height;
              uint64 consensusData;
              bytes32 prevBlockHash;
              bytes32 transactionsRoot;
              bytes32 crossStatesRoot;
              bytes32 blockRoot;
              bytes consensusPayload;
              bytes20 nextBookkeeper;
          }
      
          struct ToMerkleValue {
              bytes  txHash;  // cross chain txhash
              uint64 fromChainID;
              TxParam makeTxParam;
          }
      
          struct TxParam {
              bytes txHash; //  source chain txhash
              bytes crossChainId;
              bytes fromContract;
              uint64 toChainId;
              bytes toContract;
              bytes method;
              bytes args;
          }
      
          uint constant POLYCHAIN_PUBKEY_LEN = 67;
          uint constant POLYCHAIN_SIGNATURE_LEN = 65;
      
          /* @notice                  Verify Poly chain transaction whether exist or not
          *  @param _auditPath        Poly chain merkle proof
          *  @param _root             Poly chain root
          *  @return                  The verified value included in _auditPath
          */
          function merkleProve(bytes memory _auditPath, bytes32 _root) internal pure returns (bytes memory) {
              uint256 off = 0;
              bytes memory value;
              (value, off)  = ZeroCopySource.NextVarBytes(_auditPath, off);
      
              bytes32 hash = Utils.hashLeaf(value);
              uint size = _auditPath.length.sub(off).div(33);
              bytes32 nodeHash;
              byte pos;
              for (uint i = 0; i < size; i++) {
                  (pos, off) = ZeroCopySource.NextByte(_auditPath, off);
                  (nodeHash, off) = ZeroCopySource.NextHash(_auditPath, off);
                  if (pos == 0x00) {
                      hash = Utils.hashChildren(nodeHash, hash);
                  } else if (pos == 0x01) {
                      hash = Utils.hashChildren(hash, nodeHash);
                  } else {
                      revert("merkleProve, NextByte for position info failed");
                  }
              }
              require(hash == _root, "merkleProve, expect root is not equal actual root");
              return value;
          }
      
          /* @notice              calculate next book keeper according to public key list
          *  @param _keyLen       consensus node number
          *  @param _m            minimum signature number
          *  @param _pubKeyList   consensus node public key list
          *  @return              two element: next book keeper, consensus node signer addresses
          */
          function _getBookKeeper(uint _keyLen, uint _m, bytes memory _pubKeyList) internal pure returns (bytes20, address[] memory){
               bytes memory buff;
               buff = ZeroCopySink.WriteUint16(uint16(_keyLen));
               address[] memory keepers = new address[](_keyLen);
               bytes32 hash;
               bytes memory publicKey;
               for(uint i = 0; i < _keyLen; i++){
                   publicKey = Utils.slice(_pubKeyList, i*POLYCHAIN_PUBKEY_LEN, POLYCHAIN_PUBKEY_LEN);
                   buff =  abi.encodePacked(buff, ZeroCopySink.WriteVarBytes(Utils.compressMCPubKey(publicKey)));
                   hash = keccak256(Utils.slice(publicKey, 3, 64));
                   keepers[i] = address(uint160(uint256(hash)));
               }
      
               buff = abi.encodePacked(buff, ZeroCopySink.WriteUint16(uint16(_m)));
               bytes20  nextBookKeeper = ripemd160(abi.encodePacked(sha256(buff)));
               return (nextBookKeeper, keepers);
          }
      
          /* @notice              Verify public key derived from Poly chain
          *  @param _pubKeyList   serialized consensus node public key list
          *  @param _sigList      consensus node signature list
          *  @return              return two element: next book keeper, consensus node signer addresses
          */
          function verifyPubkey(bytes memory _pubKeyList) internal pure returns (bytes20, address[] memory) {
              require(_pubKeyList.length % POLYCHAIN_PUBKEY_LEN == 0, "_pubKeyList length illegal!");
              uint n = _pubKeyList.length / POLYCHAIN_PUBKEY_LEN;
              require(n >= 1, "too short _pubKeyList!");
              return _getBookKeeper(n, n - (n - 1) / 3, _pubKeyList);
          }
      
          /* @notice              Verify Poly chain consensus node signature
          *  @param _rawHeader    Poly chain block header raw bytes
          *  @param _sigList      consensus node signature list
          *  @param _keepers      addresses corresponding with Poly chain book keepers' public keys
          *  @param _m            minimum signature number
          *  @return              true or false
          */
          function verifySig(bytes memory _rawHeader, bytes memory _sigList, address[] memory _keepers, uint _m) internal pure returns (bool){
              bytes32 hash = getHeaderHash(_rawHeader);
      
              uint sigCount = _sigList.length.div(POLYCHAIN_SIGNATURE_LEN);
              address[] memory signers = new address[](sigCount);
              bytes32 r;
              bytes32 s;
              uint8 v;
              for(uint j = 0; j  < sigCount; j++){
                  r = Utils.bytesToBytes32(Utils.slice(_sigList, j*POLYCHAIN_SIGNATURE_LEN, 32));
                  s =  Utils.bytesToBytes32(Utils.slice(_sigList, j*POLYCHAIN_SIGNATURE_LEN + 32, 32));
                  v =  uint8(_sigList[j*POLYCHAIN_SIGNATURE_LEN + 64]) + 27;
                  signers[j] =  ecrecover(sha256(abi.encodePacked(hash)), v, r, s);
                  if (signers[j] == address(0)) return false;
              }
              return Utils.containMAddresses(_keepers, signers, _m);
          }
          
      
          /* @notice               Serialize Poly chain book keepers' info in Ethereum addresses format into raw bytes
          *  @param keepersBytes   The serialized addresses
          *  @return               serialized bytes result
          */
          function serializeKeepers(address[] memory keepers) internal pure returns (bytes memory) {
              uint256 keeperLen = keepers.length;
              bytes memory keepersBytes = ZeroCopySink.WriteUint64(uint64(keeperLen));
              for(uint i = 0; i < keeperLen; i++) {
                  keepersBytes = abi.encodePacked(keepersBytes, ZeroCopySink.WriteVarBytes(Utils.addressToBytes(keepers[i])));
              }
              return keepersBytes;
          }
      
          /* @notice               Deserialize bytes into Ethereum addresses
          *  @param keepersBytes   The serialized addresses derived from Poly chain book keepers in bytes format
          *  @return               addresses
          */
          function deserializeKeepers(bytes memory keepersBytes) internal pure returns (address[] memory) {
              uint256 off = 0;
              uint64 keeperLen;
              (keeperLen, off) = ZeroCopySource.NextUint64(keepersBytes, off);
              address[] memory keepers = new address[](keeperLen);
              bytes memory keeperBytes;
              for(uint i = 0; i < keeperLen; i++) {
                  (keeperBytes, off) = ZeroCopySource.NextVarBytes(keepersBytes, off);
                  keepers[i] = Utils.bytesToAddress(keeperBytes);
              }
              return keepers;
          }
      
          /* @notice               Deserialize Poly chain transaction raw value
          *  @param _valueBs       Poly chain transaction raw bytes
          *  @return               ToMerkleValue struct
          */
          function deserializeMerkleValue(bytes memory _valueBs) internal pure returns (ToMerkleValue memory) {
              ToMerkleValue memory toMerkleValue;
              uint256 off = 0;
      
              (toMerkleValue.txHash, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
      
              (toMerkleValue.fromChainID, off) = ZeroCopySource.NextUint64(_valueBs, off);
      
              TxParam memory txParam;
      
              (txParam.txHash, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
              
              (txParam.crossChainId, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
      
              (txParam.fromContract, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
      
              (txParam.toChainId, off) = ZeroCopySource.NextUint64(_valueBs, off);
      
              (txParam.toContract, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
      
              (txParam.method, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
      
              (txParam.args, off) = ZeroCopySource.NextVarBytes(_valueBs, off);
              toMerkleValue.makeTxParam = txParam;
      
              return toMerkleValue;
          }
      
          /* @notice            Deserialize Poly chain block header raw bytes
          *  @param _valueBs    Poly chain block header raw bytes
          *  @return            Header struct
          */
          function deserializeHeader(bytes memory _headerBs) internal pure returns (Header memory) {
              Header memory header;
              uint256 off = 0;
              (header.version, off)  = ZeroCopySource.NextUint32(_headerBs, off);
      
              (header.chainId, off) = ZeroCopySource.NextUint64(_headerBs, off);
      
              (header.prevBlockHash, off) = ZeroCopySource.NextHash(_headerBs, off);
      
              (header.transactionsRoot, off) = ZeroCopySource.NextHash(_headerBs, off);
      
              (header.crossStatesRoot, off) = ZeroCopySource.NextHash(_headerBs, off);
      
              (header.blockRoot, off) = ZeroCopySource.NextHash(_headerBs, off);
      
              (header.timestamp, off) = ZeroCopySource.NextUint32(_headerBs, off);
      
              (header.height, off) = ZeroCopySource.NextUint32(_headerBs, off);
      
              (header.consensusData, off) = ZeroCopySource.NextUint64(_headerBs, off);
      
              (header.consensusPayload, off) = ZeroCopySource.NextVarBytes(_headerBs, off);
      
              (header.nextBookkeeper, off) = ZeroCopySource.NextBytes20(_headerBs, off);
      
              return header;
          }
      
          /* @notice            Deserialize Poly chain block header raw bytes
          *  @param rawHeader   Poly chain block header raw bytes
          *  @return            header hash same as Poly chain
          */
          function getHeaderHash(bytes memory rawHeader) internal pure returns (bytes32) {
              return sha256(abi.encodePacked(sha256(rawHeader)));
          }
      }
      
      interface IEthCrossChainData {
          function putCurEpochStartHeight(uint32 curEpochStartHeight) external returns (bool);
          function getCurEpochStartHeight() external view returns (uint32);
          function putCurEpochConPubKeyBytes(bytes calldata curEpochPkBytes) external returns (bool);
          function getCurEpochConPubKeyBytes() external view returns (bytes memory);
          function markFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) external returns (bool);
          function checkIfFromChainTxExist(uint64 fromChainId, bytes32 fromChainTx) external view returns (bool);
          function getEthTxHashIndex() external view returns (uint256);
          function putEthTxHash(bytes32 ethTxHash) external returns (bool);
          function putExtraData(bytes32 key1, bytes32 key2, bytes calldata value) external returns (bool);
          function getExtraData(bytes32 key1, bytes32 key2) external view returns (bytes memory);
          function transferOwnership(address newOwner) external;
          function pause() external returns (bool);
          function unpause() external returns (bool);
          function paused() external view returns (bool);
          // Not used currently by ECCM
          function getEthTxHash(uint256 ethTxHashIndex) external view returns (bytes32);
      }
      
      interface IUpgradableECCM {
          function pause() external returns (bool);
          function unpause() external returns (bool);
          function paused() external view returns (bool);
          function upgradeToNew(address) external returns (bool);
          function isOwner() external view returns (bool);
          function setChainId(uint64 _newChainId) external returns (bool);
      }
      
      
      interface IEthCrossChainManager {
          function crossChain(uint64 _toChainId, bytes calldata _toContract, bytes calldata _method, bytes calldata _txData) external returns (bool);
      }
      
      contract UpgradableECCM is IUpgradableECCM, Ownable, Pausable {
          address public EthCrossChainDataAddress;
          uint64 public chainId;  
          
          constructor (address ethCrossChainDataAddr, uint64 _chainId) Pausable() Ownable()  public {
              EthCrossChainDataAddress = ethCrossChainDataAddr;
              chainId = _chainId;
          }
          function pause() onlyOwner public returns (bool) {
              if (!paused()) {
                  _pause();
              }
              IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);
              if (!eccd.paused()) {
                  require(eccd.pause(), "pause EthCrossChainData contract failed");
              }
              return true;
          }
          
          function unpause() onlyOwner public returns (bool) {
              if (paused()) {
                  _unpause();
              }
              IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);
              if (eccd.paused()) {
                  require(eccd.unpause(), "unpause EthCrossChainData contract failed");
              }
              return true;
          }
      
          // if we want to upgrade this contract, we need to invoke this method 
          function upgradeToNew(address newEthCrossChainManagerAddress) whenPaused onlyOwner public returns (bool) {
              IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);
              eccd.transferOwnership(newEthCrossChainManagerAddress);
              return true;
          }
          
          function setChainId(uint64 _newChainId) whenPaused onlyOwner public returns (bool) {
              chainId = _newChainId;
              return true;
          }
      }
      
      contract EthCrossChainManager is IEthCrossChainManager, UpgradableECCM {
          using SafeMath for uint256;
          
          address public whiteLister;
          mapping(address => bool) public whiteListFromContract;
          mapping(address => mapping(bytes => bool)) public whiteListContractMethodMap;
      
          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, 
              address[] memory fromContractWhiteList, 
              bytes[] memory contractMethodWhiteList
          ) UpgradableECCM(_eccd,_chainId) public {
              whiteLister = msg.sender;
              for (uint i=0;i<fromContractWhiteList.length;i++) {
                  whiteListFromContract[fromContractWhiteList[i]] = true;
              }
              for (uint i=0;i<contractMethodWhiteList.length;i++) {
                  (address toContract,bytes[] memory methods) = abi.decode(contractMethodWhiteList[i],(address,bytes[]));
                  for (uint j=0;j<methods.length;j++) {
                      whiteListContractMethodMap[toContract][methods[j]] = true;
                  }
              }
          }
          
          modifier onlyWhiteLister() {
              require(msg.sender == whiteLister, "Not whiteLister");
              _;
          }
      
          function setWhiteLister(address newWL) public onlyWhiteLister {
              require(newWL!=address(0), "Can not transfer to address(0)");
              whiteLister = newWL;
          }
          
          function setFromContractWhiteList(address[] memory fromContractWhiteList) public onlyWhiteLister {
              for (uint i=0;i<fromContractWhiteList.length;i++) {
                  whiteListFromContract[fromContractWhiteList[i]] = true;
              }
          }
          
          function removeFromContractWhiteList(address[] memory fromContractWhiteList) public onlyWhiteLister {
              for (uint i=0;i<fromContractWhiteList.length;i++) {
                  whiteListFromContract[fromContractWhiteList[i]] = false;
              }
          }
          
          function setContractMethodWhiteList(bytes[] memory contractMethodWhiteList) public onlyWhiteLister {
              for (uint i=0;i<contractMethodWhiteList.length;i++) {
                  (address toContract,bytes[] memory methods) = abi.decode(contractMethodWhiteList[i],(address,bytes[]));
                  for (uint j=0;j<methods.length;j++) {
                      whiteListContractMethodMap[toContract][methods[j]] = true;
                  }
              }
          }
          
          function removeContractMethodWhiteList(bytes[] memory contractMethodWhiteList) public onlyWhiteLister {
              for (uint i=0;i<contractMethodWhiteList.length;i++) {
                  (address toContract,bytes[] memory methods) = abi.decode(contractMethodWhiteList[i],(address,bytes[]));
                  for (uint j=0;j<methods.length;j++) {
                      whiteListContractMethodMap[toContract][methods[j]] = false;
                  }
              }
          }
      
          /* @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) {
              // Only allow whitelist contract to call
              require(whiteListFromContract[msg.sender],"Invalid from contract");
              
              // 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);
              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);
              
              // only invoke PreWhiteListed Contract and method For Now
              require(whiteListContractMethodMap[toContract][toMerkleValue.makeTxParam.method],"Invalid to contract or method");
      
              //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;
          }
      }

      File 2 of 2: DMOD
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/access/Ownable.sol
      
      //SPDX-License-Identifier: MIT
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/utils/Context.sol
      
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      /*
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with GSN meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes memory) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
          }
      }
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/token/ERC20/ERC20.sol
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/token/ERC20/IERC20.sol
      
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
      
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
      
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
      
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
      
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
      
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      
      pragma solidity >=0.6.0 <0.8.0;
      
      
      
      
      /**
       * @dev Implementation of the {IERC20} interface.
       *
       * This implementation is agnostic to the way tokens are created. This means
       * that a supply mechanism has to be added in a derived contract using {_mint}.
       * For a generic mechanism see {ERC20PresetMinterPauser}.
       *
       * TIP: For a detailed writeup see our guide
       * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * We have followed general OpenZeppelin guidelines: functions revert instead
       * of returning `false` on failure. This behavior is nonetheless conventional
       * and does not conflict with the expectations of ERC20 applications.
       *
       * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
       * This allows applications to reconstruct the allowance for all accounts just
       * by listening to said events. Other implementations of the EIP may not emit
       * these events, as it isn't required by the specification.
       *
       * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
       * functions have been added to mitigate the well-known issues around setting
       * allowances. See {IERC20-approve}.
       */
      contract ERC20 is Context, IERC20 {
          using SafeMath for uint256;
      
          mapping (address => uint256) private _balances;
      
          mapping (address => mapping (address => uint256)) private _allowances;
      
          uint256 private _totalSupply;
      
          string private _name;
          string private _symbol;
          uint8 private _decimals;
      
          /**
           * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
           * a default value of 18.
           *
           * To select a different value for {decimals}, use {_setupDecimals}.
           *
           * All three of these values are immutable: they can only be set once during
           * construction.
           */
          constructor (string memory name_, string memory symbol_) public {
              _name = name_;
              _symbol = symbol_;
              _decimals = 18;
          }
      
          /**
           * @dev Returns the name of the token.
           */
          function name() public view virtual returns (string memory) {
              return _name;
          }
      
          /**
           * @dev Returns the symbol of the token, usually a shorter version of the
           * name.
           */
          function symbol() public view virtual returns (string memory) {
              return _symbol;
          }
      
          /**
           * @dev Returns the number of decimals used to get its user representation.
           * For example, if `decimals` equals `2`, a balance of `505` tokens should
           * be displayed to a user as `5,05` (`505 / 10 ** 2`).
           *
           * Tokens usually opt for a value of 18, imitating the relationship between
           * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
           * called.
           *
           * NOTE: This information is only used for _display_ purposes: it in
           * no way affects any of the arithmetic of the contract, including
           * {IERC20-balanceOf} and {IERC20-transfer}.
           */
          function decimals() public view virtual returns (uint8) {
              return _decimals;
          }
      
          /**
           * @dev See {IERC20-totalSupply}.
           */
          function totalSupply() public view virtual override returns (uint256) {
              return _totalSupply;
          }
      
          /**
           * @dev See {IERC20-balanceOf}.
           */
          function balanceOf(address account) public view virtual override returns (uint256) {
              return _balances[account];
          }
      
          /**
           * @dev See {IERC20-transfer}.
           *
           * Requirements:
           *
           * - `recipient` cannot be the zero address.
           * - the caller must have a balance of at least `amount`.
           */
          function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
              _transfer(_msgSender(), recipient, amount);
              return true;
          }
      
          /**
           * @dev See {IERC20-allowance}.
           */
          function allowance(address owner, address spender) public view virtual override returns (uint256) {
              return _allowances[owner][spender];
          }
      
          /**
           * @dev See {IERC20-approve}.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function approve(address spender, uint256 amount) public virtual override returns (bool) {
              _approve(_msgSender(), spender, amount);
              return true;
          }
      
          /**
           * @dev See {IERC20-transferFrom}.
           *
           * Emits an {Approval} event indicating the updated allowance. This is not
           * required by the EIP. See the note at the beginning of {ERC20}.
           *
           * Requirements:
           *
           * - `sender` and `recipient` cannot be the zero address.
           * - `sender` must have a balance of at least `amount`.
           * - the caller must have allowance for ``sender``'s tokens of at least
           * `amount`.
           */
          function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
              _transfer(sender, recipient, amount);
              _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
              return true;
          }
      
          /**
           * @dev Atomically increases the allowance granted to `spender` by the caller.
           *
           * This is an alternative to {approve} that can be used as a mitigation for
           * problems described in {IERC20-approve}.
           *
           * Emits an {Approval} event indicating the updated allowance.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
              _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
              return true;
          }
      
          /**
           * @dev Atomically decreases the allowance granted to `spender` by the caller.
           *
           * This is an alternative to {approve} that can be used as a mitigation for
           * problems described in {IERC20-approve}.
           *
           * Emits an {Approval} event indicating the updated allowance.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `spender` must have allowance for the caller of at least
           * `subtractedValue`.
           */
          function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
              _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
              return true;
          }
      
          /**
           * @dev Moves tokens `amount` from `sender` to `recipient`.
           *
           * This is internal function is equivalent to {transfer}, and can be used to
           * e.g. implement automatic token fees, slashing mechanisms, etc.
           *
           * Emits a {Transfer} event.
           *
           * Requirements:
           *
           * - `sender` cannot be the zero address.
           * - `recipient` cannot be the zero address.
           * - `sender` must have a balance of at least `amount`.
           */
          function _transfer(address sender, address recipient, uint256 amount) internal virtual {
              require(sender != address(0), "ERC20: transfer from the zero address");
              require(recipient != address(0), "ERC20: transfer to the zero address");
      
              _beforeTokenTransfer(sender, recipient, amount);
      
              _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
              _balances[recipient] = _balances[recipient].add(amount);
              emit Transfer(sender, recipient, amount);
          }
      
          /** @dev Creates `amount` tokens and assigns them to `account`, increasing
           * the total supply.
           *
           * Emits a {Transfer} event with `from` set to the zero address.
           *
           * Requirements:
           *
           * - `to` cannot be the zero address.
           */
          function _mint(address account, uint256 amount) internal virtual {
              require(account != address(0), "ERC20: mint to the zero address");
      
              _beforeTokenTransfer(address(0), account, amount);
      
              _totalSupply = _totalSupply.add(amount);
              _balances[account] = _balances[account].add(amount);
              emit Transfer(address(0), account, amount);
          }
      
          /**
           * @dev Destroys `amount` tokens from `account`, reducing the
           * total supply.
           *
           * Emits a {Transfer} event with `to` set to the zero address.
           *
           * Requirements:
           *
           * - `account` cannot be the zero address.
           * - `account` must have at least `amount` tokens.
           */
          function _burn(address account, uint256 amount) internal virtual {
              require(account != address(0), "ERC20: burn from the zero address");
      
              _beforeTokenTransfer(account, address(0), amount);
      
              _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
              _totalSupply = _totalSupply.sub(amount);
              emit Transfer(account, address(0), amount);
          }
      
          /**
           * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
           *
           * This internal function is equivalent to `approve`, and can be used to
           * e.g. set automatic allowances for certain subsystems, etc.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `owner` cannot be the zero address.
           * - `spender` cannot be the zero address.
           */
          function _approve(address owner, address spender, uint256 amount) internal virtual {
              require(owner != address(0), "ERC20: approve from the zero address");
              require(spender != address(0), "ERC20: approve to the zero address");
      
              _allowances[owner][spender] = amount;
              emit Approval(owner, spender, amount);
          }
      
          /**
           * @dev Sets {decimals} to a value other than the default one of 18.
           *
           * WARNING: This function should only be called from the constructor. Most
           * applications that interact with token contracts will not expect
           * {decimals} to ever change, and may work incorrectly if it does.
           */
          function _setupDecimals(uint8 decimals_) internal virtual {
              _decimals = decimals_;
          }
      
          /**
           * @dev Hook that is called before any transfer of tokens. This includes
           * minting and burning.
           *
           * Calling conditions:
           *
           * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
           * will be to transferred to `to`.
           * - when `from` is zero, `amount` tokens will be minted for `to`.
           * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
           * - `from` and `to` are never both zero.
           *
           * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
           */
          function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
      }
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor () internal {
              address msgSender = _msgSender();
              _owner = msgSender;
              emit OwnershipTransferred(address(0), msgSender);
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(owner() == _msgSender(), "Ownable: caller is not the owner");
              _;
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
      }
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/token/ERC20/ERC20Capped.sol
      
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      
      /**
       * @dev Extension of {ERC20} that adds a cap to the supply of tokens.
       */
      abstract contract ERC20Capped is ERC20 {
          using SafeMath for uint256;
      
          uint256 private _cap;
      
          /**
           * @dev Sets the value of the `cap`. This value is immutable, it can only be
           * set once during construction.
           */
          constructor (uint256 cap_) internal {
              require(cap_ > 0, "ERC20Capped: cap is 0");
              _cap = cap_;
          }
      
          /**
           * @dev Returns the cap on the token's total supply.
           */
          function cap() public view virtual returns (uint256) {
              return _cap;
          }
      
          /**
           * @dev See {ERC20-_beforeTokenTransfer}.
           *
           * Requirements:
           *
           * - minted tokens must not cause the total supply to go over the cap.
           */
          function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
              super._beforeTokenTransfer(from, to, amount);
      
              if (from == address(0)) { // When minting tokens
                  require(totalSupply().add(amount) <= cap(), "ERC20Capped: cap exceeded");
              }
          }
      }
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/math/SafeMath.sol
      
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              uint256 c = a + b;
              if (c < a) return (false, 0);
              return (true, c);
          }
      
          /**
           * @dev Returns the substraction of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b > a) return (false, 0);
              return (true, a - b);
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
           *
           * _Available since v3.4._
           */
          function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) return (true, 0);
              uint256 c = a * b;
              if (c / a != b) return (false, 0);
              return (true, c);
          }
      
          /**
           * @dev Returns the division of two unsigned integers, with a division by zero flag.
           *
           * _Available since v3.4._
           */
          function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b == 0) return (false, 0);
              return (true, a / b);
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
           *
           * _Available since v3.4._
           */
          function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
              if (b == 0) return (false, 0);
              return (true, a % b);
          }
      
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           *
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
              return c;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b <= a, "SafeMath: subtraction overflow");
              return a - b;
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           *
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
              return c;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers, reverting on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: division by zero");
              return a / b;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b > 0, "SafeMath: modulo by zero");
              return a % b;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {trySub}.
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           *
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              return a - b;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers, reverting with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryDiv}.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a / b;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * reverting with custom message when dividing by zero.
           *
           * CAUTION: This function is deprecated because it requires allocating memory for the error
           * message unnecessarily. For custom revert reasons use {tryMod}.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           *
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              return a % b;
          }
      }
      
      // File: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.4/contracts/token/ERC20/ERC20Burnable.sol
      
      
      
      pragma solidity >=0.6.0 <0.8.0;
      
      
      
      /**
       * @dev Extension of {ERC20} that allows token holders to destroy both their own
       * tokens and those that they have an allowance for, in a way that can be
       * recognized off-chain (via event analysis).
       */
      abstract contract ERC20Burnable is Context, ERC20 {
          using SafeMath for uint256;
      
          /**
           * @dev Destroys `amount` tokens from the caller.
           *
           * See {ERC20-_burn}.
           */
          function burn(uint256 amount) public virtual {
              _burn(_msgSender(), amount);
          }
      
          /**
           * @dev Destroys `amount` tokens from `account`, deducting from the caller's
           * allowance.
           *
           * See {ERC20-_burn} and {ERC20-allowance}.
           *
           * Requirements:
           *
           * - the caller must have allowance for ``accounts``'s tokens of at least
           * `amount`.
           */
          function burnFrom(address account, uint256 amount) public virtual {
              uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
      
              _approve(account, _msgSender(), decreasedAllowance);
              _burn(account, amount);
          }
      }
      
      // File: DMOD.sol
      
      
      pragma solidity ^0.7.1; 
      
      
      
      
      contract DMOD is ERC20Burnable, ERC20Capped, Ownable{
        constructor(address dmodMultiSig)
              public
              ERC20("Demodyfi Token", "DMOD")
              ERC20Capped(100000000 * 10**18)
          {
              transferOwnership(dmodMultiSig);
          }
      
          function mint(address recipient, uint256 amount) public onlyOwner {
              _mint(recipient, amount);
          }
      
          function _beforeTokenTransfer(
              address from,
              address to,
              uint256 amount
          ) internal virtual override(ERC20Capped, ERC20) {
              ERC20Capped._beforeTokenTransfer(from, to, amount);
          }
      }