Skip to content

Commit

Permalink
feat: permit method
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin-fruitful committed Oct 30, 2024
1 parent 7932920 commit 18b94f3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
57 changes: 57 additions & 0 deletions src/facets/NaymsTokenFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,61 @@ contract NaymsTokenFacet is Modifiers {
AppStorage storage s = LibAppStorage.diamondStorage();
return s.minter;
}

/// @dev The EIP-712 typehash for the permit struct used by the contract
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

/**
* @dev See {IERC20Permit-permit}.
*/
function permit(
address _owner,
address _spender,
uint256 _value,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
)
external
{
AppStorage storage s = LibAppStorage.diamondStorage();

if (block.timestamp > _deadline) {
revert("ERC20Permit: expired deadline");
}

bytes32 structHash =
keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _value, s.nonces[_owner]++, _deadline));

bytes32 hash = keccak256(abi.encodePacked("\x19\x01", s.DOMAIN_SEPARATOR, structHash));

address signer = ecrecover(hash, _v, _r, _s);
if (signer == address(0) || signer != _owner) {
revert("ERC20Permit: invalid signature");
}

LibERC20Token._approve(_owner, _spender, _value, true);
}

/**
* @dev Returns the current nonce for `owner`. This value must be included whenever a signature is generated for
* {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256) {
AppStorage storage s = LibAppStorage.diamondStorage();
return s.nonces[owner];
}

/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
function DOMAIN_SEPARATOR() external view returns (bytes32) {
AppStorage storage s = LibAppStorage.diamondStorage();
return s.DOMAIN_SEPARATOR;
}
}
31 changes: 31 additions & 0 deletions src/init/InitPermit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { AppStorage, LibAppStorage } from "../shared/AppStorage.sol";

contract InitPermit {
function init() external {
uint256 initId = 2; // Using ID 2 since InitializationTest1 used ID 1

AppStorage storage s = LibAppStorage.diamondStorage();
require(!s.initComplete[initId], "Initialization already complete");

// Initialize the domain separator and chain id
s.initialChainId = block.chainid;
s.initialDomainSeparator = _computeDomainSeparator();

s.initComplete[initId] = true;
}

function _computeDomainSeparator() internal view returns (bytes32) {
return keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("Naym")), // name
keccak256(bytes("1")), // version
block.chainid,
address(this)
)
);
}
}
2 changes: 2 additions & 0 deletions src/shared/AppStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct AppStorage {
address minter;
// upgrade initializations
mapping(uint256 => bool) initComplete;
bytes32 DOMAIN_SEPARATOR;
mapping(address permitCaller => uint256 nonce) nonces;
}

library LibAppStorage {
Expand Down

0 comments on commit 18b94f3

Please sign in to comment.