ETH Price: $1,897.17 (-1.56%)

Transaction Decoder

Block:
18960958 at Jan-08-2024 07:56:35 AM +UTC
Transaction Fee:
0.003247205833624632 ETH $6.16
Gas Used:
125,823 Gas / 25.807728584 Gwei

Emitted Events:

362 CATERC20.Transfer( from=[Receiver] 0x95deb8f818f0f01805451fa6bf391b0f97b4d033, to=[Sender] 0x9967ac7939b128e6933c6de94b65e8b42a77c404, value=2000000000000000000000 )
363 0x95deb8f818f0f01805451fa6bf391b0f97b4d033.0x8e3a3c9cb1053e365062561003e3cf87b3de309aff9d418c06a7327098537e41( 0x8e3a3c9cb1053e365062561003e3cf87b3de309aff9d418c06a7327098537e41, 0x0000000000000000000000009967ac7939b128e6933c6de94b65e8b42a77c404, 00000000000000000000000000000000000000000000006c6b935b8bbd400000, 0000000000000000000000000000000000000000000000000000000000000002 )

Account State Difference:

  Address   Before After State Difference Code
(beaverbuild)
17.652387101528430689 Eth17.652389401588598564 Eth0.000002300060167875
0x95dEB8F8...F97B4d033
0x9967AC79...42A77C404
0.629227524203460442 Eth
Nonce: 249
0.62598031836983581 Eth
Nonce: 250
0.003247205833624632
0xb4357054...C7f090343

Execution Trace

0x95deb8f818f0f01805451fa6bf391b0f97b4d033.4ab5b187( )
  • 0x6a82d3ced72c4f5368772a7fd0870dfb946dabd7.4ab5b187( )
    • Null: 0x000...001.bd681b0f( )
    • CATERC20.balanceOf( account=0x95dEB8F818f0f01805451fa6bf391B0F97B4d033 ) => ( 33795055563569155092592596 )
    • CATERC20.transfer( to=0x9967AC7939b128E6933C6de94B65E8B42A77C404, amount=2000000000000000000000 ) => ( True )
      // File: contracts/contracts/cat/ERC20/Structs.sol
      
      // contracts/Structs.sol
      
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.10;
      
      
      contract CATERC20Structs {
          struct CrossChainPayload {
              // Amount being transferred (big-endian uint256)
              uint256 amount;
              // Address of the token. Left-zero-padded if shorter than 32 bytes
              bytes32 tokenAddress;
              // Chain ID of the token
              uint16 tokenChain;
              // Address of the recipient. Left-zero-padded if shorter than 32 bytes
              bytes32 toAddress;
              // Chain ID of the recipient
              uint16 toChain;
              // Token Decimals of sender chain
              uint8 tokenDecimals;
          }
      
          struct SignatureVerification {
              // Address of custodian the user has delegated to sign transaction on behalf of
              address custodian;
              // Timestamp the transaction will be valid till
              uint256 validTill;
              // Signed Signature
              bytes signature;
          }
      }
      
      // File: contracts/contracts/cat/ERC20/State.sol
      
      // contracts/State.sol
      
      
      
      
      contract CATERC20Events {
          event bridgeInEvent(
              uint256 tokenAmount,
              uint256 fromChain,
              uint256 toChain,
              bytes32 indexed toAddress
          );
      
          event bridgeOutEvent(
              uint256 tokenAmount,
              uint256 fromChain,
              uint256 toChain,
              bytes32 indexed fromAddress,
              bytes32 indexed toAddress
          );
      }
      
      contract CATERC20Storage {
          struct Provider {
              uint16 chainId;
              // Required number of block confirmations to assume finality
              uint8 finality;
          }
      
          struct State {
              Provider provider;
              address payable wormhole;
              // Mapping of consumed token transfers
              mapping(bytes32 => bool) completedTransfers;
              // Mapping of token contracts on other chains
              mapping(uint16 => bytes32) tokenImplementations;
              // EIP-155 Chain ID
              uint256 evmChainId;
              address nativeAsset;
              bool isInitialized;
              uint8 decimals;
              uint256 maxSupply;
              uint256 mintedSupply;
              // Mapping for storing used signatures
              mapping(bytes => bool) signaturesUsed;
          }
      }
      
      contract CATERC20State {
          CATERC20Storage.State _state;
      }
      
      // File: contracts/contracts/cat/ERC20/Setters.sol
      
      // contracts/Setters.sol
      
      
      
      
      
      contract CATERC20Setters is CATERC20State {
          function setTransferCompleted(bytes32 hash) internal {
              _state.completedTransfers[hash] = true;
          }
      
          function setTokenImplementation(uint16 chainId, bytes32 tokenContract) internal {
              _state.tokenImplementations[chainId] = tokenContract;
          }
      
          function setWormhole(address wh) internal {
              _state.wormhole = payable(wh);
          }
      
          function setFinality(uint8 finality) internal {
              _state.provider.finality = finality;
          }
      
          function setChainId(uint16 chainId) internal {
              _state.provider.chainId = chainId;
          }
      
          function setEvmChainId(uint256 evmChainId) internal {
              require(evmChainId == block.chainid, "invalid evmChainId");
              _state.evmChainId = evmChainId;
          }
      
          function setDecimals(uint8 decimals) internal {
              _state.decimals = decimals;
          }
      
          function setMaxSupply(uint256 maxSupply) internal {
              _state.maxSupply = maxSupply;
          }
      
          function setMintedSupply(uint256 mintedSupply) internal {
              _state.mintedSupply = mintedSupply;
          }
      
          function setNativeAsset(address nativeAsset) internal {
              _state.nativeAsset = nativeAsset;
          }
      
          function setIsInitialized() internal {
              _state.isInitialized = true;
          }
      
          function setSignatureUsed(bytes memory signature) internal {
              _state.signaturesUsed[signature] = true;
          }
      }
      
      // File: contracts/contracts/libraries/external/BytesLib.sol
      
      
      /*
       * @title Solidity Bytes Arrays Utils
       * @author Gonçalo Sá <goncalo.sa@consensys.net>
       *
       * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
       *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
       */
      
      
      library BytesLib {
          function concat(
              bytes memory _preBytes,
              bytes memory _postBytes
          )
              internal
              pure
              returns (bytes memory)
          {
              bytes memory tempBytes;
      
              assembly {
                  // Get a location of some free memory and store it in tempBytes as
                  // Solidity does for memory variables.
                  tempBytes := mload(0x40)
      
                  // Store the length of the first bytes array at the beginning of
                  // the memory for tempBytes.
                  let length := mload(_preBytes)
                  mstore(tempBytes, length)
      
                  // Maintain a memory counter for the current write location in the
                  // temp bytes array by adding the 32 bytes for the array length to
                  // the starting location.
                  let mc := add(tempBytes, 0x20)
                  // Stop copying when the memory counter reaches the length of the
                  // first bytes array.
                  let end := add(mc, length)
      
                  for {
                      // Initialize a copy counter to the start of the _preBytes data,
                      // 32 bytes into its memory.
                      let cc := add(_preBytes, 0x20)
                  } lt(mc, end) {
                      // Increase both counters by 32 bytes each iteration.
                      mc := add(mc, 0x20)
                      cc := add(cc, 0x20)
                  } {
                      // Write the _preBytes data into the tempBytes memory 32 bytes
                      // at a time.
                      mstore(mc, mload(cc))
                  }
      
                  // Add the length of _postBytes to the current length of tempBytes
                  // and store it as the new length in the first 32 bytes of the
                  // tempBytes memory.
                  length := mload(_postBytes)
                  mstore(tempBytes, add(length, mload(tempBytes)))
      
                  // Move the memory counter back from a multiple of 0x20 to the
                  // actual end of the _preBytes data.
                  mc := end
                  // Stop copying when the memory counter reaches the new combined
                  // length of the arrays.
                  end := add(mc, length)
      
                  for {
                      let cc := add(_postBytes, 0x20)
                  } lt(mc, end) {
                      mc := add(mc, 0x20)
                      cc := add(cc, 0x20)
                  } {
                      mstore(mc, mload(cc))
                  }
      
                  // Update the free-memory pointer by padding our last write location
                  // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
                  // next 32 byte block, then round down to the nearest multiple of
                  // 32. If the sum of the length of the two arrays is zero then add
                  // one before rounding down to leave a blank 32 bytes (the length block with 0).
                  mstore(0x40, and(
                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                    not(31) // Round down to the nearest 32 bytes.
                  ))
              }
      
              return tempBytes;
          }
      
          function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
              assembly {
                  // Read the first 32 bytes of _preBytes storage, which is the length
                  // of the array. (We don't need to use the offset into the slot
                  // because arrays use the entire slot.)
                  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)
                  let newlength := add(slength, mlength)
                  // slength can contain both the length and contents of the array
                  // if length < 32 bytes so let's prepare for that
                  // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                  switch add(lt(slength, 32), lt(newlength, 32))
                  case 2 {
                      // Since the new array still fits in the slot, we just need to
                      // update the contents of the slot.
                      // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                      sstore(
                          _preBytes.slot,
                          // all the modifications to the slot are inside this
                          // next block
                          add(
                              // we can just add to the slot contents because the
                              // bytes we want to change are the LSBs
                              fslot,
                              add(
                                  mul(
                                      div(
                                          // load the bytes from memory
                                          mload(add(_postBytes, 0x20)),
                                          // zero all bytes to the right
                                          exp(0x100, sub(32, mlength))
                                      ),
                                      // and now shift left the number of bytes to
                                      // leave space for the length in the slot
                                      exp(0x100, sub(32, newlength))
                                  ),
                                  // increase length by the double of the memory
                                  // bytes length
                                  mul(mlength, 2)
                              )
                          )
                      )
                  }
                  case 1 {
                      // The stored value fits in the slot, but the combined value
                      // will exceed it.
                      // get the keccak hash to get the contents of the array
                      mstore(0x0, _preBytes.slot)
                      let sc := add(keccak256(0x0, 0x20), div(slength, 32))
      
                      // save new length
                      sstore(_preBytes.slot, add(mul(newlength, 2), 1))
      
                      // The contents of the _postBytes array start 32 bytes into
                      // the structure. Our first read should obtain the `submod`
                      // bytes that can fit into the unused space in the last word
                      // of the stored array. To get this, we read 32 bytes starting
                      // from `submod`, so the data we read overlaps with the array
                      // contents by `submod` bytes. Masking the lowest-order
                      // `submod` bytes allows us to add that value directly to the
                      // stored value.
      
                      let submod := sub(32, slength)
                      let mc := add(_postBytes, submod)
                      let end := add(_postBytes, mlength)
                      let mask := sub(exp(0x100, submod), 1)
      
                      sstore(
                          sc,
                          add(
                              and(
                                  fslot,
                                  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                              ),
                              and(mload(mc), mask)
                          )
                      )
      
                      for {
                          mc := add(mc, 0x20)
                          sc := add(sc, 1)
                      } lt(mc, end) {
                          sc := add(sc, 1)
                          mc := add(mc, 0x20)
                      } {
                          sstore(sc, mload(mc))
                      }
      
                      mask := exp(0x100, sub(mc, end))
      
                      sstore(sc, mul(div(mload(mc), mask), mask))
                  }
                  default {
                      // get the keccak hash to get the contents of the array
                      mstore(0x0, _preBytes.slot)
                      // Start copying to the last used word of the stored array.
                      let sc := add(keccak256(0x0, 0x20), div(slength, 32))
      
                      // save new length
                      sstore(_preBytes.slot, add(mul(newlength, 2), 1))
      
                      // Copy over the first `submod` bytes of the new data as in
                      // case 1 above.
                      let slengthmod := mod(slength, 32)
                      let mlengthmod := mod(mlength, 32)
                      let submod := sub(32, slengthmod)
                      let mc := add(_postBytes, submod)
                      let end := add(_postBytes, mlength)
                      let mask := sub(exp(0x100, submod), 1)
      
                      sstore(sc, add(sload(sc), and(mload(mc), mask)))
      
                      for {
                          sc := add(sc, 1)
                          mc := add(mc, 0x20)
                      } lt(mc, end) {
                          sc := add(sc, 1)
                          mc := add(mc, 0x20)
                      } {
                          sstore(sc, mload(mc))
                      }
      
                      mask := exp(0x100, sub(mc, end))
      
                      sstore(sc, mul(div(mload(mc), mask), mask))
                  }
              }
          }
      
          function slice(
              bytes memory _bytes,
              uint256 _start,
              uint256 _length
          )
              internal
              pure
              returns (bytes memory)
          {
              require(_length + 31 >= _length, "slice_overflow");
              require(_bytes.length >= _start + _length, "slice_outOfBounds");
      
              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.
                      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)
                      //zero out the 32 bytes slice we are about to return
                      //we need to do it because Solidity does not garbage collect
                      mstore(tempBytes, 0)
      
                      mstore(0x40, add(tempBytes, 0x20))
                  }
              }
      
              return tempBytes;
          }
      
          function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
              require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
              address tempAddress;
      
              assembly {
                  tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
              }
      
              return tempAddress;
          }
      
          function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
              require(_bytes.length >= _start + 1 , "toUint8_outOfBounds");
              uint8 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x1), _start))
              }
      
              return tempUint;
          }
      
          function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
              require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
              uint16 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x2), _start))
              }
      
              return tempUint;
          }
      
          function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
              require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
              uint32 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x4), _start))
              }
      
              return tempUint;
          }
      
          function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
              require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
              uint64 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x8), _start))
              }
      
              return tempUint;
          }
      
          function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
              require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
              uint96 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0xc), _start))
              }
      
              return tempUint;
          }
      
          function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
              require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
              uint128 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x10), _start))
              }
      
              return tempUint;
          }
      
          function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
              require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
              uint256 tempUint;
      
              assembly {
                  tempUint := mload(add(add(_bytes, 0x20), _start))
              }
      
              return tempUint;
          }
      
          function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
              require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
              bytes32 tempBytes32;
      
              assembly {
                  tempBytes32 := mload(add(add(_bytes, 0x20), _start))
              }
      
              return tempBytes32;
          }
      
          function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
              bool success = true;
      
              assembly {
                  let length := mload(_preBytes)
      
                  // if lengths don't match the arrays are not equal
                  switch eq(length, mload(_postBytes))
                  case 1 {
                      // 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
      
                      let mc := add(_preBytes, 0x20)
                      let end := add(mc, length)
      
                      for {
                          let cc := add(_postBytes, 0x20)
                      // the next line is the loop condition:
                      // while(uint256(mc < end) + cb == 2)
                      } eq(add(lt(mc, end), cb), 2) {
                          mc := add(mc, 0x20)
                          cc := add(cc, 0x20)
                      } {
                          // if any of these checks fails then arrays are not equal
                          if iszero(eq(mload(mc), mload(cc))) {
                              // unsuccess:
                              success := 0
                              cb := 0
                          }
                      }
                  }
                  default {
                      // unsuccess:
                      success := 0
                  }
              }
      
              return success;
          }
      
          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)
                  // Decode the length of the stored array like in concatStorage().
                  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 {
                      // slength can contain both the length and contents of the array
                      // if length < 32 bytes so let's prepare for that
                      // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                      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(uint256(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;
          }
      }
      
      // File: contracts/contracts/cat/interfaces/ICATERC20.sol
      
      
      
      
      interface ICATERC20 {
          function initialize(
              uint16 chainId,
              address wormhole,
              uint8 finality,
              uint256 maxSupply
          ) external;
      
          /**
           * @dev To bridge tokens to other chains.
           */
          function bridgeOut(
              uint256 amount,
              uint16 recipientChain,
              bytes32 recipient,
              uint32 nonce
          ) external payable returns (uint64 sequence);
      
          function bridgeIn(bytes memory encodedVm) external returns (bytes memory);
      
          function mint(address recipient, uint256 amount) external;
      }
      
      // File: contracts/contracts/interfaces/IWormhole.sol
      
      // contracts/Messages.sol
      
      
      
      
      interface IWormhole {
          struct GuardianSet {
              address[] keys;
              uint32 expirationTime;
          }
      
          struct Signature {
              bytes32 r;
              bytes32 s;
              uint8 v;
              uint8 guardianIndex;
          }
      
          struct VM {
              uint8 version;
              uint32 timestamp;
              uint32 nonce;
              uint16 emitterChainId;
              bytes32 emitterAddress;
              uint64 sequence;
              uint8 consistencyLevel;
              bytes payload;
      
              uint32 guardianSetIndex;
              Signature[] signatures;
      
              bytes32 hash;
          }
      
          struct TransferFees {
              bytes32 module;
              uint8 action;
              uint16 chain;
      
              uint256 amount;
              bytes32 recipient;
          }
      
          event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);
          function publishMessage(
              uint32 nonce,
              bytes memory payload,
              uint8 consistencyLevel
          ) external payable returns (uint64 sequence);
      
          function parseAndVerifyVM(bytes calldata encodedVM) external view returns (VM memory vm, bool valid, string memory reason);
      
          function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);
      
          function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet) external pure returns (bool valid, string memory reason);
      
          function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);
      
          function isInitialized(address impl) external view returns (bool);
      
          function chainId() external view returns (uint16);
      
          function governanceChainId() external view returns (uint16);
      
          function governanceContract() external view returns (bytes32);
      
          function messageFee() external view returns (uint256);
      
          function evmChainId() external view returns (uint256);
      
      }
      
      // File: contracts/contracts/cat/shared/WormholeStructs.sol
      
      // contracts/shared/WormholeStructs.sol
      
      
      
      
      interface WormholeStructs {
          struct Provider {
              uint16 chainId;
              uint16 governanceChainId;
              bytes32 governanceContract;
          }
      
          struct GuardianSet {
              address[] keys;
              uint32 expirationTime;
          }
      
          struct Signature {
              bytes32 r;
              bytes32 s;
              uint8 v;
              uint8 guardianIndex;
          }
      
          struct VM {
              uint8 version;
              uint32 timestamp;
              uint32 nonce;
              uint16 emitterChainId;
              bytes32 emitterAddress;
              uint64 sequence;
              uint8 consistencyLevel;
              bytes payload;
              uint32 guardianSetIndex;
              Signature[] signatures;
              bytes32 hash;
          }
      }
      
      // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
      
      
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
      
      
      
      /**
       * @dev Interface of the ERC165 standard, as defined in the
       * https://eips.ethereum.org/EIPS/eip-165[EIP].
       *
       * Implementers can declare support of contract interfaces, which can then be
       * queried by others ({ERC165Checker}).
       *
       * For an implementation, see {ERC165}.
       */
      interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
      }
      
      // File: @openzeppelin/contracts/utils/introspection/ERC165.sol
      
      
      // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
      
      
      
      
      /**
       * @dev Implementation of the {IERC165} interface.
       *
       * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
       * for the additional interface id that will be supported. For example:
       *
       * ```solidity
       * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
       *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
       * }
       * ```
       *
       * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
       */
      abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
              return interfaceId == type(IERC165).interfaceId;
          }
      }
      
      // File: @openzeppelin/contracts/utils/Context.sol
      
      
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      
      
      
      /**
       * @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 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) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      
      // File: @openzeppelin/contracts/access/Ownable.sol
      
      
      // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
      
      
      
      
      /**
       * @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() {
              _transferOwnership(_msgSender());
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              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 {
              _transferOwnership(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");
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      
      // File: @openzeppelin/contracts/utils/Address.sol
      
      
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
      
      
      
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is 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.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
      
              return account.code.length > 0;
          }
      
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
      
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
      
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, "Address: low-level call failed");
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
      
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionDelegateCall(target, data, "Address: low-level delegate call failed");
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
      
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
           *
           * _Available since v4.8._
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              if (success) {
                  if (returndata.length == 0) {
                      // only check isContract if the call was successful and the return data is empty
                      // otherwise we already know that it was a contract
                      require(isContract(target), "Address: call to non-contract");
                  }
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
      
          /**
           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason or using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
      
          function _revert(bytes memory returndata, string memory errorMessage) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert(errorMessage);
              }
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
      
      
      // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
      
      
      
      /**
       * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       */
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
      
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
      
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      
      // File: @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
      
      
      // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol)
      
      
      
      // EIP-2612 is Final as of 2022-11-01. This file is deprecated.
      
      
      // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
      
      
      // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
      
      
      
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @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);
      
          /**
           * @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 `to`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address to, 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 `from` to `to` 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 from,
              address to,
              uint256 amount
          ) external returns (bool);
      }
      
      // File: contracts/contracts/cat/interfaces/IERC20Extended.sol
      
      
      
      
      
      interface IERC20Extended is IERC20 {
          function decimals() external view returns (uint8);
      }
      
      // File: contracts/contracts/cat/ERC20/Getters.sol
      
      // contracts/Getters.sol
      
      
      
      
      
      
      
      
      contract CATERC20Getters is CATERC20State {
          using BytesLib for bytes;
      
          function isTransferCompleted(bytes32 hash) public view returns (bool) {
              return _state.completedTransfers[hash];
          }
      
          function wormhole() public view returns (IWormhole) {
              return IWormhole(_state.wormhole);
          }
      
          function chainId() public view returns (uint16) {
              return _state.provider.chainId;
          }
      
          function evmChainId() public view returns (uint256) {
              return _state.evmChainId;
          }
      
          function tokenContracts(uint16 chainId_) public view returns (bytes32) {
              return _state.tokenImplementations[chainId_];
          }
      
          function finality() public view returns (uint8) {
              return _state.provider.finality;
          }
      
          function getDecimals() public view returns (uint8) {
              return _state.decimals;
          }
      
          function maxSupply() public view returns (uint256) {
              return _state.maxSupply;
          }
      
          function mintedSupply() public view returns (uint256) {
              return _state.mintedSupply;
          }
      
          function nativeAsset() public view returns (IERC20Extended) {
              return IERC20Extended(_state.nativeAsset);
          }
      
          function isInitialized() public view returns (bool) {
              return _state.isInitialized;
          }
      
          function isSignatureUsed(bytes memory signature) public view returns (bool) {
              return _state.signaturesUsed[signature];
          }
      
          function normalizeAmount(
              uint256 amount,
              uint8 foreignDecimals,
              uint8 localDecimals
          ) internal pure returns (uint256) {
              if (foreignDecimals > localDecimals) {
                  amount /= 10 ** (foreignDecimals - localDecimals);
              }
              if (localDecimals > foreignDecimals) {
                  amount *= 10 ** (localDecimals - foreignDecimals);
              }
              return amount;
          }
      
          /*
           * @dev Truncate a 32 byte array to a 20 byte address.
           *      Reverts if the array contains non-0 bytes in the first 12 bytes.
           *
           * @param bytes32 bytes The 32 byte array to be converted.
           */
          function bytesToAddress(bytes32 b) public pure returns (address) {
              require(bytes12(b) == 0, "invalid EVM address");
              return address(uint160(uint256(b)));
          }
      
          function addressToBytes(address a) public pure returns (bytes32) {
              return bytes32(uint256(uint160(a)));
          }
      
          function encodeTransfer(
              CATERC20Structs.CrossChainPayload memory transfer
          ) public pure returns (bytes memory encoded) {
              encoded = abi.encodePacked(
                  transfer.amount,
                  transfer.tokenAddress,
                  transfer.tokenChain,
                  transfer.toAddress,
                  transfer.toChain,
                  transfer.tokenDecimals
              );
          }
      
          function decodeTransfer(
              bytes memory encoded
          ) public pure returns (CATERC20Structs.CrossChainPayload memory transfer) {
              uint index = 0;
      
              transfer.amount = encoded.toUint256(index);
              index += 32;
      
              transfer.tokenAddress = encoded.toBytes32(index);
              index += 32;
      
              transfer.tokenChain = encoded.toUint16(index);
              index += 2;
      
              transfer.toAddress = encoded.toBytes32(index);
              index += 32;
      
              transfer.toChain = encoded.toUint16(index);
              index += 2;
      
              transfer.tokenDecimals = encoded.toUint8(index);
              index += 1;
      
              require(encoded.length == index, "invalid Transfer");
          }
      }
      
      // File: contracts/contracts/cat/ERC20/Governance.sol
      
      // contracts/Bridge.sol
      
      
      
      
      
      
      
      
      
      
      contract CATERC20Governance is CATERC20Getters, CATERC20Setters, Ownable {
          /// builds a prefixed hash to mimic the behavior of eth_sign.
          function prefixed(bytes32 _hash) internal pure returns (bytes32) {
              return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
          }
      
          /// signature methods.
          function splitSignature(
              bytes memory sig
          ) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
              require(sig.length == 65);
      
              assembly {
                  // first 32 bytes, after the length prefix.
                  r := mload(add(sig, 32))
                  // second 32 bytes.
                  s := mload(add(sig, 64))
                  // final byte (first byte of the next 32 bytes).
                  v := byte(0, mload(add(sig, 96)))
              }
      
              return (v, r, s);
          }
      
          function verifySignature(
              bytes32 message,
              bytes memory signature,
              address authority
          ) internal pure returns (bool) {
              (uint8 v, bytes32 r, bytes32 s) = splitSignature(signature);
              address recovered = ecrecover(message, v, r, s);
              if (recovered == authority) {
                  return true;
              } else {
                  return false;
              }
          }
      
          /// @dev verify owner is caller or the caller has valid owner signature
          modifier onlyOwnerOrOwnerSignature(
              CATERC20Structs.SignatureVerification memory signatureArguments
          ) {
              if (_msgSender() == owner()) {
                  _;
              } else {
                  bytes32 encodedHashData = prefixed(
                      keccak256(
                          abi.encodePacked(signatureArguments.custodian, signatureArguments.validTill)
                      )
                  );
                  require(signatureArguments.custodian == _msgSender(), "custodian can call only");
                  require(signatureArguments.validTill > block.timestamp, "signed transaction expired");
                  require(
                      isSignatureUsed(signatureArguments.signature) == false,
                      "cannot re-use signatures"
                  );
                  setSignatureUsed(signatureArguments.signature);
                  require(
                      verifySignature(encodedHashData, signatureArguments.signature, owner()),
                      "unauthorized signature"
                  );
                  _;
              }
          }
      
          // Execute a RegisterChain governance message
          function registerChain(
              uint16 chainId,
              bytes32 tokenContract,
              CATERC20Structs.SignatureVerification memory signatureArguments
          ) public onlyOwnerOrOwnerSignature(signatureArguments) {
              setTokenImplementation(chainId, tokenContract);
          }
      
          function registerChains(
              uint16[] memory chainId,
              bytes32[] memory tokenContract,
              CATERC20Structs.SignatureVerification memory signatureArguments
          ) public onlyOwnerOrOwnerSignature(signatureArguments) {
              require(chainId.length == tokenContract.length, "Invalid Input");
              for (uint256 i = 0; i < tokenContract.length; i++) {
                  setTokenImplementation(chainId[i], tokenContract[i]);
              }
          }
      
          // Execute a RegisterChain governance message
          function updateFinality(
              uint8 finality,
              CATERC20Structs.SignatureVerification memory signatureArguments
          ) public onlyOwnerOrOwnerSignature(signatureArguments) {
              setFinality(finality);
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
      
      
      // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
      
      
      
      
      /**
       * @dev Interface for the optional metadata functions from the ERC20 standard.
       *
       * _Available since v4.1._
       */
      interface IERC20Metadata is IERC20 {
          /**
           * @dev Returns the name of the token.
           */
          function name() external view returns (string memory);
      
          /**
           * @dev Returns the symbol of the token.
           */
          function symbol() external view returns (string memory);
      
          /**
           * @dev Returns the decimals places of the token.
           */
          function decimals() external view returns (uint8);
      }
      
      // File: @openzeppelin/contracts/token/ERC20/ERC20.sol
      
      
      // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
      
      
      
      
      
      
      /**
       * @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.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
       * to implement supply mechanisms].
       *
       * We have followed general OpenZeppelin Contracts guidelines: functions revert
       * instead 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, IERC20Metadata {
          mapping(address => uint256) private _balances;
      
          mapping(address => mapping(address => uint256)) private _allowances;
      
          uint256 private _totalSupply;
      
          string private _name;
          string private _symbol;
      
          /**
           * @dev Sets the values for {name} and {symbol}.
           *
           * The default value of {decimals} is 18. To select a different value for
           * {decimals} you should overload it.
           *
           * All two of these values are immutable: they can only be set once during
           * construction.
           */
          constructor(string memory name_, string memory symbol_) {
              _name = name_;
              _symbol = symbol_;
          }
      
          /**
           * @dev Returns the name of the token.
           */
          function name() public view virtual override returns (string memory) {
              return _name;
          }
      
          /**
           * @dev Returns the symbol of the token, usually a shorter version of the
           * name.
           */
          function symbol() public view virtual override 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 this function is
           * overridden;
           *
           * 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 override returns (uint8) {
              return 18;
          }
      
          /**
           * @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:
           *
           * - `to` cannot be the zero address.
           * - the caller must have a balance of at least `amount`.
           */
          function transfer(address to, uint256 amount) public virtual override returns (bool) {
              address owner = _msgSender();
              _transfer(owner, to, 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}.
           *
           * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
           * `transferFrom`. This is semantically equivalent to an infinite approval.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           */
          function approve(address spender, uint256 amount) public virtual override returns (bool) {
              address owner = _msgSender();
              _approve(owner, 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}.
           *
           * NOTE: Does not update the allowance if the current allowance
           * is the maximum `uint256`.
           *
           * Requirements:
           *
           * - `from` and `to` cannot be the zero address.
           * - `from` must have a balance of at least `amount`.
           * - the caller must have allowance for ``from``'s tokens of at least
           * `amount`.
           */
          function transferFrom(
              address from,
              address to,
              uint256 amount
          ) public virtual override returns (bool) {
              address spender = _msgSender();
              _spendAllowance(from, spender, amount);
              _transfer(from, to, amount);
              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) {
              address owner = _msgSender();
              _approve(owner, spender, allowance(owner, spender) + 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) {
              address owner = _msgSender();
              uint256 currentAllowance = allowance(owner, spender);
              require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
              unchecked {
                  _approve(owner, spender, currentAllowance - subtractedValue);
              }
      
              return true;
          }
      
          /**
           * @dev Moves `amount` of tokens from `from` to `to`.
           *
           * This 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:
           *
           * - `from` cannot be the zero address.
           * - `to` cannot be the zero address.
           * - `from` must have a balance of at least `amount`.
           */
          function _transfer(
              address from,
              address to,
              uint256 amount
          ) internal virtual {
              require(from != address(0), "ERC20: transfer from the zero address");
              require(to != address(0), "ERC20: transfer to the zero address");
      
              _beforeTokenTransfer(from, to, amount);
      
              uint256 fromBalance = _balances[from];
              require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
              unchecked {
                  _balances[from] = fromBalance - amount;
                  // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
                  // decrementing then incrementing.
                  _balances[to] += amount;
              }
      
              emit Transfer(from, to, amount);
      
              _afterTokenTransfer(from, to, 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:
           *
           * - `account` 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 += amount;
              unchecked {
                  // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
                  _balances[account] += amount;
              }
              emit Transfer(address(0), account, amount);
      
              _afterTokenTransfer(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);
      
              uint256 accountBalance = _balances[account];
              require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
              unchecked {
                  _balances[account] = accountBalance - amount;
                  // Overflow not possible: amount <= accountBalance <= totalSupply.
                  _totalSupply -= amount;
              }
      
              emit Transfer(account, address(0), amount);
      
              _afterTokenTransfer(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 Updates `owner` s allowance for `spender` based on spent `amount`.
           *
           * Does not update the allowance amount in case of infinite allowance.
           * Revert if not enough allowance is available.
           *
           * Might emit an {Approval} event.
           */
          function _spendAllowance(
              address owner,
              address spender,
              uint256 amount
          ) internal virtual {
              uint256 currentAllowance = allowance(owner, spender);
              if (currentAllowance != type(uint256).max) {
                  require(currentAllowance >= amount, "ERC20: insufficient allowance");
                  unchecked {
                      _approve(owner, spender, currentAllowance - amount);
                  }
              }
          }
      
          /**
           * @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 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 {}
      
          /**
           * @dev Hook that is called after any transfer of tokens. This includes
           * minting and burning.
           *
           * Calling conditions:
           *
           * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
           * has been transferred to `to`.
           * - when `from` is zero, `amount` tokens have been minted for `to`.
           * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
              address from,
              address to,
              uint256 amount
          ) internal virtual {}
      }
      
      // File: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
      
      
      // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
      
      
      
      
      
      
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
      
          function safeTransfer(
              IERC20 token,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
      
          function safeTransferFrom(
              IERC20 token,
              address from,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
      
          /**
           * @dev Deprecated. This function has issues similar to the ones found in
           * {IERC20-approve}, and its usage is discouraged.
           *
           * Whenever possible, use {safeIncreaseAllowance} and
           * {safeDecreaseAllowance} instead.
           */
          function safeApprove(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              // safeApprove should only be called when setting an initial allowance,
              // or when resetting it to zero. To increase and decrease it, use
              // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
              require(
                  (value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
      
          function safeIncreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              uint256 newAllowance = token.allowance(address(this), spender) + value;
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
      
          function safeDecreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              unchecked {
                  uint256 oldAllowance = token.allowance(address(this), spender);
                  require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                  uint256 newAllowance = oldAllowance - value;
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
          }
      
          function safePermit(
              IERC20Permit token,
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal {
              uint256 nonceBefore = token.nonces(owner);
              token.permit(owner, spender, value, deadline, v, r, s);
              uint256 nonceAfter = token.nonces(owner);
              require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
      
              bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
              if (returndata.length > 0) {
                  // Return data is optional
                  require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
              }
          }
      }
      
      // File: contracts/contracts/cat/ERC20/CATERC20.sol
      
      
      
      
      
      
      
      
      
      
      
      
      
      contract CATERC20 is Context, ERC20, CATERC20Governance, CATERC20Events, ERC165 {
      	using SafeERC20 for IERC20;
      	
      	constructor(string memory name, string memory symbol, uint8 decimal) ERC20(name, symbol) {
      		setEvmChainId(block.chainid);
      		setDecimals(decimal);
      	}
      	
      	function initialize(
      		uint16 chainId,
      		address wormhole,
      		uint8 finality,
      		uint256 maxSupply
      	) public onlyOwner {
      		require(isInitialized() == false, "Already Initialized");
      		
      		setChainId(chainId);
      		setWormhole(wormhole);
      		setFinality(finality);
      		setMaxSupply(maxSupply);
      		setMintedSupply(0);
      		setIsInitialized();
      	}
      	
      	function decimals() public view virtual override returns (uint8) {
      		return getDecimals();
      	}
      	
      	function supportsInterface(
      		bytes4 interfaceId
      	) public view virtual override(ERC165) returns (bool) {
      		return interfaceId == type(ICATERC20).interfaceId || super.supportsInterface(interfaceId);
      	}
      	
      	/**
      	 * @dev To bridge tokens to other chains.
           */
      	function bridgeOut(
      		uint256 amount,
      		uint16 recipientChain,
      		bytes32 recipient,
      		uint32 nonce
      	) external payable returns (uint64 sequence) {
      		require(isInitialized() == true, "Not Initialized");
      		require(evmChainId() == block.chainid, "unsupported fork");
      		
      		uint256 fee = wormhole().messageFee();
      		require(msg.value >= fee, "Not enough fee provided to publish message");
      		uint16 tokenChain = wormhole().chainId();
      		bytes32 tokenAddress = bytes32(uint256(uint160(address(this))));
      		
      		_burn(_msgSender(), amount);
      		
      		CATERC20Structs.CrossChainPayload memory transfer = CATERC20Structs.CrossChainPayload({
      			amount: amount,
      			tokenAddress: tokenAddress,
      			tokenChain: tokenChain,
      			toAddress: recipient,
      			toChain: recipientChain,
      			tokenDecimals: getDecimals()
      		});
      		
      		sequence = wormhole().publishMessage{value: msg.value}(
      			nonce,
      			encodeTransfer(transfer),
      			finality()
      		);
      		
      		emit bridgeOutEvent(
      			amount,
      			tokenChain,
      			recipientChain,
      			addressToBytes(_msgSender()),
      			recipient
      		);
      	} // end of function
      	
      	function bridgeIn(bytes memory encodedVm) external returns (bytes memory) {
      		require(isInitialized() == true, "Not Initialized");
      		require(evmChainId() == block.chainid, "unsupported fork");
      		
      		(IWormhole.VM memory vm, bool valid, string memory reason) = wormhole().parseAndVerifyVM(
      			encodedVm
      		);
      		require(valid, reason);
      		require(
      			bytesToAddress(vm.emitterAddress) == address(this) ||
      			tokenContracts(vm.emitterChainId) == vm.emitterAddress,
      			"Invalid Emitter"
      		);
      		
      		CATERC20Structs.CrossChainPayload memory transfer = decodeTransfer(vm.payload);
      		address transferRecipient = bytesToAddress(transfer.toAddress);
      		
      		require(!isTransferCompleted(vm.hash), "transfer already completed");
      		setTransferCompleted(vm.hash);
      		
      		require(transfer.toChain == wormhole().chainId(), "invalid target chain");
      		
      		uint256 nativeAmount = normalizeAmount(
      			transfer.amount,
      			transfer.tokenDecimals,
      			getDecimals()
      		);
      		
      		_mint(transferRecipient, nativeAmount);
      		
      		emit bridgeInEvent(nativeAmount, transfer.tokenChain, transfer.toChain, transfer.toAddress);
      		
      		return vm.payload;
      	}
      	
      	function mint(address recipient, uint256 amount) public onlyOwner {
      		require(mintedSupply() + amount <= maxSupply(), "MAX SUPPLY REACHED");
      		setMintedSupply(mintedSupply() + amount);
      		_mint(recipient, amount);
      	}
      }