Revocation Enforcer
The RevocationEnforcer.sol
smart contract allows the delegator (owner) to revoke his signed delegation immediately.
Deployments
- Mainnet: Coming Soon
- Polygon: Coming Soon
- Optimism: Coming Soon
How It Works
- The delegator needs to include the
RevocationEnforcer
caveat, in the (signed) delegation - otherwise he won't be able to revoke his delegation later. - If the delegator decides to revoke the delegation, he needs to call
revocationEnforcer.revokeDelegation(signedDelegation, domainHash)
. He has to submit that tx himself.
Javascript Example-1: including the revocation caveat
const delegation = {
delegate: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', // vitalik.eth
authority:
'0x0000000000000000000000000000000000000000000000000000000000000000',
caveats: [
{
enforcer: RevocationEnforcer.address,
terms: '0x00',
},
],
};
Javascript Example-2: revoking a delegation
let tx = await revocationEnforcer
.connect(delegator)
.revokeDelegation(signedDelegation, domainHash);
await tx.wait();
Smart Contract
contract RevocationEnforcer is
CaveatEnforcer,
Delegatable("RevocationEnforcer", "1")
{
mapping(bytes32 => bool) isRevoked;
function enforceCaveat(
bytes calldata _terms,
Transaction calldata _transaction,
bytes32 delegationHash
) public view override returns (bool) {
require(!isRevoked[delegationHash], "RevocationEnforcer:revoked");
return true;
}
function revokeDelegation(
SignedDelegation calldata signedDelegation,
bytes32 domainHash
) public {
address signer = verifyExternalDelegationSignature(
signedDelegation,
domainHash
);
address sender = _msgSender();
console.log("Sender is ", sender);
console.log("signer is ", signer);
console.log("msg sender is ", msg.sender);
require(signer == sender, "RevocationEnforcer:invalid-revoker");
bytes32 delegationHash = GET_SIGNEDDELEGATION_PACKETHASH(
signedDelegation
);
isRevoked[delegationHash] = true;
}
function verifyExternalDelegationSignature(
SignedDelegation memory signedDelegation,
bytes32 domainHash
) public view virtual returns (address) {
Delegation memory delegation = signedDelegation.delegation;
bytes32 sigHash = getExternalDelegationTypedDataHash(
delegation,
domainHash
);
address recoveredSignatureSigner = recover(
sigHash,
signedDelegation.signature
);
return recoveredSignatureSigner;
}
function getExternalDelegationTypedDataHash(
Delegation memory delegation,
bytes32 domainHash
) public pure returns (bytes32) {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
domainHash,
GET_DELEGATION_PACKETHASH(delegation)
)
);
return digest;
}
/**
* This is boilerplate that must be added to any Delegatable contract if it also inherits
* from another class that also implements _msgSender().
*/
function _msgSender() internal view override returns (address sender) {
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
} else {
sender = msg.sender;
}
return sender;
}
}