Skip to content

Instantly share code, notes, and snippets.

@partylikeits1983
Created December 3, 2023 09:50
Show Gist options
  • Save partylikeits1983/23243cd8ae07a0f24355f9f0b2decd72 to your computer and use it in GitHub Desktop.
Save partylikeits1983/23243cd8ae07a0f24355f9f0b2decd72 to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
contract DelegatedSignature {
// gameAddress => uint16 moves
mapping(address => uint16[]) public userData; // on chain data
// AUTHORIZE DELEGATED SIGNER FUNCTIONS
function getEthSignedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
}
function verifyDelegatedAddress(
bytes32 delegatedAddressBytes,
bytes memory signature,
address delegatorAddress,
address delegatedAddress
) public pure {
bytes32 delegatedAddressHash = hashDelegatedAddress(delegatedAddress);
require(delegatedAddressHash == delegatedAddressBytes);
bytes32 ethSignedMessageHash = getEthSignedMessageHash(delegatedAddressBytes);
require(
ECDSA.recover(ethSignedMessageHash, signature) == delegatorAddress,
"Delegated signature verification failed"
);
}
function encodeDelegation(
bytes32 delegatedAddressBytes,
bytes memory signature,
address delegatorAddress,
address delegatedAddress
) public pure returns (bytes memory) {
return abi.encode(delegatedAddressBytes, signature, delegatorAddress, delegatedAddress);
}
function decodeDelegation(bytes memory delegation) internal pure returns (bytes32, bytes memory, address, address) {
return abi.decode(delegation, (bytes32, bytes, address, address));
}
function hashDelegatedAddress(address delegator) public pure returns (bytes32) {
return keccak256(abi.encodePacked(delegator));
}
function verifyDelegation(bytes memory delegation) public pure returns (address, address) {
(
bytes32 delegatedAddressBytes,
bytes memory signature,
address delegatorAddress,
address delegatedAddress
) = decodeDelegation(delegation);
verifyDelegatedAddress(delegatedAddressBytes, signature, delegatorAddress, delegatedAddress);
return (delegatorAddress, delegatedAddress);
}
// DELEGATED SIGNER FUNCTIONS
function writeToStateOnBehalfOfDelegator(
bytes memory delegation,
bytes memory moveData,
bytes memory moveSignature
) public {
(, address delegatedAddress) = verifyDelegation(delegation);
(address gameAddress, uint16 move, uint gameNumber, uint expiration) = decodeMoveData(moveData);
bytes32 moveDataHash = hashMoveData(gameAddress, move, gameNumber, expiration);
verifyMove(moveDataHash, moveSignature, delegatedAddress);
uint moveLength = userData[gameAddress].length;
uint16[] memory newMoves = new uint16[](moveLength + 1);
newMoves[moveLength] = move;
userData[gameAddress] = newMoves;
}
function encodeMoveData(
address gameAddress,
uint16 move,
uint gameNumber,
uint expiration
) public pure returns (bytes memory) {
return abi.encode(gameAddress, move, gameNumber, expiration);
}
function decodeMoveData(bytes memory moveData) internal pure returns (address, uint16, uint, uint) {
return abi.decode(moveData, (address, uint16, uint, uint));
}
function hashMoveData(address wager, uint16 move, uint moveNumber, uint expiration) public pure returns (bytes32) {
return keccak256(abi.encodePacked(encodeMoveData(wager, move, moveNumber, expiration)));
}
function verifyMove(bytes32 moveDataHash, bytes memory moveSignature, address delegatorAddress) internal pure {
bytes32 ethSignedMessageHash = getEthSignedMessageHash(moveDataHash);
require(ECDSA.recover(ethSignedMessageHash, moveSignature) == delegatorAddress, "invalid sig");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment