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; | |
} | |
} |
Updated contract's deployment details:
Please use ๐ contracts if you need to get signer addresses back in bytes[]
form
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
New revision to return checkpoint signer addresses in
bytes[]
form instead ofaddress[]
.๐ change is being made to address issue faced in Matic Network's The Graph deployment, where it requires addresses in
Array<Bytes>
form & conversion fromArray<Address>
toArray<Bytes>
fails in runtime.An issue was created in
graph-ts
repo, reporting this.But this change probably solves aforementioned problem ๐.