Skip to content

[WIP] feat: add possibility to handle transactions by signature #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions contracts/Distributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ contract Distributor is UUPSHelper {
/// @dev If the mapping is empty, by default rewards will accrue on the user address
mapping(address => mapping(address => address)) public claimRecipient;

bytes32 public constant SET_CLAIM_TYPEHASH =
keccak256("SetClaimRecipient(address user,address recipient,address token,uint256 deadline)");

bytes32 public constant TOGGLE_OPERATOR_TYPEHASH =
keccak256("ToggleOperator(address user,address operator,uint256 deadline)");

bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

uint256[36] private __gap;

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -244,6 +253,67 @@ contract Distributor is UUPSHelper {
emit ClaimRecipientUpdated(msg.sender, recipient, token);
}

function getDomainSeparator() public view returns (bytes32 domainSeparator) {
domainSeparator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes("MerklDistributor")),
keccak256(bytes("1")),
block.chainid,
address(this)
)
);
}

// New function with signature verification (added for upgrade)
function toggleOperatorWithSig(
address user,
address operator,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
// Create the hash to match the signature
bytes32 structHash = keccak256(abi.encode(TOGGLE_OPERATOR_TYPEHASH, user, operator, deadline));

bytes32 digest = keccak256(abi.encodePacked("\x19\x01", getDomainSeparator(), structHash));

// Recover the signer from the signature
address recovered = ecrecover(digest, v, r, s);
if (recovered == address(0) || recovered != user || block.timestamp > deadline)
revert Errors.InvalidSignature();

// Now toggle the operator as per original logic
uint256 oldValue = operators[user][operator];
operators[user][operator] = 1 - oldValue;
emit OperatorToggled(user, operator, oldValue == 0);
}

function setClaimRecipientWithSig(
address user,
address recipient,
address token,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
// Create the hash to match the signature
bytes32 structHash = keccak256(abi.encode(SET_CLAIM_TYPEHASH, user, recipient, token, deadline));

bytes32 digest = keccak256(abi.encodePacked("\x19\x01", getDomainSeparator(), structHash));

// Recover the signer from the signature
address recovered = ecrecover(digest, v, r, s);
if (recovered == address(0) || recovered != user || block.timestamp > deadline)
revert Errors.InvalidSignature();

// Set the claim recipient
claimRecipient[user][token] = recipient;
emit ClaimRecipientUpdated(user, recipient, token);
}

/// @notice Freezes the Merkle tree update until the dispute is resolved
/// @dev Requires a deposit of `disputeToken` that'll be slashed if the dispute is not accepted
/// @dev It is only possible to create a dispute within `disputePeriod` after each tree update
Expand Down Expand Up @@ -375,8 +445,12 @@ contract Distributor is UUPSHelper {
bytes memory data = datas[i];

// Only approved operator can claim for `user`
if (msg.sender != user && tx.origin != user && operators[user][msg.sender] == 0)
revert Errors.NotWhitelisted();
if (
msg.sender != user &&
tx.origin != user &&
operators[user][msg.sender] == 0 &&
operators[user][tx.origin] == 0
) revert Errors.NotWhitelisted();

// Verifying proof
bytes32 leaf = keccak256(abi.encode(user, token, amount));
Expand Down