ERC20Allowance eEnforcer
We created an ERC20Delegatable
contract (inherits from ERC20
and Delegatable
), to better illustrate the Delegatable Framework
's ERC20Permit
's functionality, and then some - through the use of Enforcers
.
Deployments
- Mainnet: Coming Soon
- Polygon: Coming Soon
- Optimism: Coming Soon
How It Works
- deploy an ERC20Delegatable contract
- deploy an ERC20AllowanceEnforcer, through which delegators can approve delegates to spend on their behalf
Smart Contracts
contract ERC20Delegatable is ERC20, Delegatable {
constructor(
string memory name,
string memory symbol,
uint256 amount
) Delegatable(name, "1") ERC20(name, symbol) {
_mint(msg.sender, amount);
}
function _msgSender()
internal
view
override(DelegatableCore, Context)
returns (address sender)
{
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
} else {
sender = msg.sender;
}
return sender;
}
}
contract ERC20AllowanceEnforcer is CaveatEnforcer {
mapping(address => mapping(bytes32 => uint256)) spentMap;
/**
* @notice Allows the delegator to specify a maximum sum of the contract token to transfer on their behalf.
* @param terms - The numeric maximum allowance that the recipient may transfer on the signer's behalf.
* @param transaction - The transaction the delegate might try to perform.
* @param delegationHash - The hash of the delegation being operated on.
*/
function enforceCaveat(
bytes calldata terms,
Transaction calldata transaction,
bytes32 delegationHash
) public override returns (bool) {
bytes4 targetSig = bytes4(transaction.data[0:4]);
bytes4 allowedSig = bytes4(0xa9059cbb);
require(
targetSig == allowedSig,
"ERC20AllowanceEnforcer:invalid-method"
);
uint256 limit = BytesLib.toUint256(terms, 0);
uint256 sending = BytesLib.toUint256(transaction.data, 36);
spentMap[msg.sender][delegationHash] += sending;
uint256 spent = spentMap[msg.sender][delegationHash];
require(spent <= limit, "ERC20AllowanceEnforcer:allowance-exceeded");
return true;
}
}
Javascript Example
const delegation = {
delegate: '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', // vitalik.eth
authority:
'0x0000000000000000000000000000000000000000000000000000000000000000',
caveats: [
{
enforcer: ERC20AllowanceEnforcer.address,
terms: ethers.utils.hexZeroPad(utils.parseEther('0.5').toHexString(), 32),
},
],
};