Last active
February 8, 2021 12:25
-
-
Save itzmeanjan/5b7c6e973bc0785018cce100ee68fee7 to your computer and use it in GitHub Desktop.
Smart contract for decoding Matic Network's check point signer addresses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
contract DecodeCheckpointSignerList { | |
// Slice specified number of bytes from arbitrary length byte array, starting from certain index | |
function slice(bytes memory payload, uint256 start, uint256 length) internal pure returns (bytes memory) { | |
require(length + 31 >= length, "slice_overflow"); | |
require(start + length >= start, "slice_overflow"); | |
require(payload.length >= start + length, "slice_outOfBounds"); | |
bytes memory tempBytes; | |
assembly { | |
switch iszero(length) | |
case 0 { | |
tempBytes := mload(0x40) | |
let lengthmod := and(length, 31) | |
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) | |
let end := add(mc, length) | |
for { | |
let cc := add(add(add(payload, lengthmod), mul(0x20, iszero(lengthmod))), start) | |
} lt(mc, end) { | |
mc := add(mc, 0x20) | |
cc := add(cc, 0x20) | |
} { | |
mstore(mc, mload(cc)) | |
} | |
mstore(tempBytes, length) | |
mstore(0x40, and(add(mc, 31), not(31))) | |
} | |
default { | |
tempBytes := mload(0x40) | |
mstore(tempBytes, 0) | |
mstore(0x40, add(tempBytes, 0x20)) | |
} | |
} | |
return tempBytes; | |
} | |
// Given input data for transaction invoking `submitHeaderBlock(bytes data, bytes sigs)` | |
// attempts to extract out data & signature fields | |
// | |
// Note: Function signature is also included in `payload` i.e. first 4 bytes, which will be | |
// stripped out 👇 | |
function decodeIntoDataAndSignature(bytes calldata payload) internal pure returns (bytes memory, bytes memory) { | |
return abi.decode(slice(payload, 4, payload.length - 4), (bytes, bytes)); | |
} | |
// Given 👆 function call for extracting `data` from transaction input data | |
// has succeeded, votehash can be computed, which was signed by these check point signers | |
function computeVoteHash(bytes memory payload) internal pure returns (bytes32) { | |
return keccak256(abi.encodePacked(hex"01", payload)); | |
} | |
// Attempt to recover signer address, given original message & signed message | |
function ecrecovery(bytes32 voteHash, bytes memory sig) internal pure returns (bytes memory) { | |
bytes32 r; | |
bytes32 s; | |
uint8 v; | |
assembly { | |
r := mload(add(sig, 32)) | |
s := mload(add(sig, 64)) | |
v := and(mload(add(sig, 65)), 255) | |
} | |
if (v < 27) v += 27; | |
return addresstoBytes(ecrecover(voteHash, v, r, s)); | |
} | |
// Converts Ethereum address to bytes data type | |
function addresstoBytes(address a) internal pure returns (bytes memory) { | |
return abi.encodePacked(a); | |
} | |
// Passing transaction input data of `submitHeaderBlock(bytes data, bytes sigs)` function | |
// call, it attempts to figure out what are those signers who signer this checkpoint | |
// | |
// Note: Sending checkpoint from Matic Network ( L2 ) to Ethereum Network ( L1 ) | |
// is nothing but calling `submitHeaderBlock(bytes data, bytes sigs)`, defined | |
// in RootChain contract, deployed on Ethereum Network, with proper arguments, by some validator. | |
// | |
// RootChain : | |
// 0x2890bA17EfE978480615e330ecB65333b880928e [ Goerli ] | |
// 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287 [ Ethereum Mainnet ] | |
function decode(bytes calldata payload) external pure returns (bytes[] memory) { | |
(bytes memory data, bytes memory sigs) = decodeIntoDataAndSignature(payload); | |
bytes32 voteHash = computeVoteHash(data); | |
bytes[] memory signers = new bytes[](sigs.length / 65); | |
uint256 count = 0; | |
for(uint256 i = 0; i < sigs.length; i += 65) { | |
signers[count++] = ecrecovery(voteHash, slice(sigs, i, 65)); | |
} | |
return signers; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated contract's deployment details:
Please use 👆 contracts if you need to get signer addresses back in
bytes[]
form