86 lines
2.9 KiB
Solidity
86 lines
2.9 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.28;
|
|
|
|
import "@openzeppelin/contracts/utils/Strings.sol";
|
|
|
|
/**
|
|
* @title TransitionMintLib
|
|
* @notice Library for handling transition minting logic
|
|
*/
|
|
library TransitionMintLib {
|
|
function getEthSignedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
|
|
/*
|
|
Signature is produced by signing a keccak256 hash with the following format:
|
|
"\x19Ethereum Signed Message\n" + len(msg) + msg
|
|
*/
|
|
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
|
|
}
|
|
|
|
function toString(address x) internal pure returns (string memory) {
|
|
bytes memory s = new bytes(40);
|
|
for (uint i = 0; i < 20; i++) {
|
|
bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i)))));
|
|
bytes1 hi = bytes1(uint8(b) / 16);
|
|
bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
|
|
s[2 * i] = char(hi);
|
|
s[2 * i + 1] = char(lo);
|
|
}
|
|
return string(s);
|
|
}
|
|
|
|
function char(bytes1 b) internal pure returns (bytes1 c) {
|
|
if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);
|
|
else return bytes1(uint8(b) + 0x57);
|
|
}
|
|
|
|
function messageHash(
|
|
address holder,
|
|
uint256 snapshotQuantity
|
|
) internal pure returns (bytes32) {
|
|
return keccak256(abi.encodePacked(
|
|
"10grans migration address: ",
|
|
toString(holder),
|
|
" wei: ",
|
|
Strings.toString(snapshotQuantity)
|
|
));
|
|
}
|
|
|
|
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) internal pure returns (address) {
|
|
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
|
|
return ecrecover(_ethSignedMessageHash, v, r, s);
|
|
}
|
|
|
|
function splitSignature(bytes memory sig) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
|
|
require(sig.length == 65, "invalid signature length");
|
|
|
|
assembly {
|
|
/*
|
|
First 32 bytes stores the length of the signature
|
|
|
|
add(sig, 32) = pointer of sig + 32
|
|
effectively, skips first 32 bytes of signature
|
|
|
|
mload(p) loads next 32 bytes starting at the memory address p into memory
|
|
*/
|
|
|
|
// 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)))
|
|
}
|
|
}
|
|
|
|
function verifyMintSignature(
|
|
address holder,
|
|
uint256 snapshotQuantity,
|
|
bytes memory signature,
|
|
address signer
|
|
) internal pure returns (bool) {
|
|
bytes32 mh = messageHash(holder, snapshotQuantity);
|
|
bytes32 ethSignedMessageHash = getEthSignedMessageHash(mh);
|
|
return recoverSigner(ethSignedMessageHash, signature) == signer;
|
|
}
|
|
}
|