Skip to content

Commit 92deebd

Browse files
Krishang NadgaudaKrishang Nadgauda
authored andcommitted
Add upgradeable versions of SignatureMint contracts
1 parent f932274 commit 92deebd

File tree

4 files changed

+312
-0
lines changed

4 files changed

+312
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "./interface/ISignatureMintERC1155.sol";
5+
6+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
7+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
8+
9+
abstract contract SignatureMintERC1155Upgradeable is Initializable, EIP712Upgradeable, ISignatureMintERC1155 {
10+
using ECDSAUpgradeable for bytes32;
11+
12+
bytes32 internal constant TYPEHASH =
13+
keccak256(
14+
"MintRequest(address to,address royaltyRecipient,uint256 royaltyBps,address primarySaleRecipient,uint256 tokenId,string uri,uint256 quantity,uint256 pricePerToken,address currency,uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid)"
15+
);
16+
17+
/// @dev Mapping from mint request UID => whether the mint request is processed.
18+
mapping(bytes32 => bool) private minted;
19+
20+
function __SignatureMintERC1155_init() internal onlyInitializing {
21+
__EIP712_init("SignatureMintERC1155", "1");
22+
}
23+
24+
function __SignatureMintERC1155_init_unchained() internal onlyInitializing {}
25+
26+
/// @dev Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).
27+
function verify(MintRequest calldata _req, bytes calldata _signature)
28+
public
29+
view
30+
returns (bool success, address signer)
31+
{
32+
signer = _recoverAddress(_req, _signature);
33+
success = !minted[_req.uid] && _isAuthorizedSigner(signer);
34+
}
35+
36+
/// @dev Returns whether a given address is authorized to sign mint requests.
37+
function _isAuthorizedSigner(address _signer) internal view virtual returns (bool);
38+
39+
/// @dev Verifies a mint request and marks the request as minted.
40+
function _processRequest(MintRequest calldata _req, bytes calldata _signature)
41+
internal
42+
returns (address signer)
43+
{
44+
bool success;
45+
(success, signer) = verify(_req, _signature);
46+
47+
require(success, "Invalid request");
48+
require(
49+
_req.validityStartTimestamp <= block.timestamp && block.timestamp <= _req.validityEndTimestamp,
50+
"Request expired"
51+
);
52+
53+
minted[_req.uid] = true;
54+
}
55+
56+
/// @dev Returns the address of the signer of the mint request.
57+
function _recoverAddress(MintRequest calldata _req, bytes calldata _signature) internal view returns (address) {
58+
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
59+
}
60+
61+
/// @dev Resolves 'stack too deep' error in `recoverAddress`.
62+
function _encodeRequest(MintRequest calldata _req) internal pure returns (bytes memory) {
63+
return
64+
abi.encode(
65+
TYPEHASH,
66+
_req.to,
67+
_req.royaltyRecipient,
68+
_req.royaltyBps,
69+
_req.primarySaleRecipient,
70+
_req.tokenId,
71+
keccak256(bytes(_req.uri)),
72+
_req.quantity,
73+
_req.pricePerToken,
74+
_req.currency,
75+
_req.validityStartTimestamp,
76+
_req.validityEndTimestamp,
77+
_req.uid
78+
);
79+
}
80+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "./interface/ISignatureMintERC20.sol";
5+
6+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
7+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
8+
9+
abstract contract SignatureMintERC20Upgradeable is Initializable, EIP712Upgradeable, ISignatureMintERC20 {
10+
using ECDSAUpgradeable for bytes32;
11+
12+
bytes32 private constant TYPEHASH =
13+
keccak256(
14+
"MintRequest(address to,address primarySaleRecipient,uint256 quantity,uint256 pricePerToken,address currency,uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid)"
15+
);
16+
17+
/// @dev Mapping from mint request UID => whether the mint request is processed.
18+
mapping(bytes32 => bool) private minted;
19+
20+
function __SignatureMintERC20_init() internal onlyInitializing {
21+
__EIP712_init("SignatureMintERC20", "1");
22+
}
23+
24+
function __SignatureMintERC20_init_unchained() internal onlyInitializing {}
25+
26+
/// @dev Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).
27+
function verify(MintRequest calldata _req, bytes calldata _signature)
28+
public
29+
view
30+
returns (bool success, address signer)
31+
{
32+
signer = _recoverAddress(_req, _signature);
33+
success = !minted[_req.uid] && _isAuthorizedSigner(signer);
34+
}
35+
36+
/// @dev Returns whether a given address is authorized to sign mint requests.
37+
function _isAuthorizedSigner(address _signer) internal view virtual returns (bool);
38+
39+
/// @dev Verifies a mint request and marks the request as minted.
40+
function _processRequest(MintRequest calldata _req, bytes calldata _signature)
41+
internal
42+
returns (address signer)
43+
{
44+
bool success;
45+
(success, signer) = verify(_req, _signature);
46+
47+
require(success, "Invalid request");
48+
require(
49+
_req.validityStartTimestamp <= block.timestamp && block.timestamp <= _req.validityEndTimestamp,
50+
"Request expired"
51+
);
52+
53+
minted[_req.uid] = true;
54+
}
55+
56+
/// @dev Returns the address of the signer of the mint request.
57+
function _recoverAddress(MintRequest calldata _req, bytes calldata _signature) internal view returns (address) {
58+
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
59+
}
60+
61+
/// @dev Resolves 'stack too deep' error in `recoverAddress`.
62+
function _encodeRequest(MintRequest calldata _req) internal pure returns (bytes memory) {
63+
return
64+
abi.encode(
65+
TYPEHASH,
66+
_req.to,
67+
_req.primarySaleRecipient,
68+
_req.quantity,
69+
_req.pricePerToken,
70+
_req.currency,
71+
_req.validityStartTimestamp,
72+
_req.validityEndTimestamp,
73+
_req.uid
74+
);
75+
}
76+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
pragma solidity ^0.8.0;
3+
4+
import "./interface/ISignatureMintERC721.sol";
5+
6+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
7+
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
8+
9+
abstract contract SignatureMintERC721Upgradeable is Initializable, EIP712Upgradeable, ISignatureMintERC721 {
10+
using ECDSAUpgradeable for bytes32;
11+
12+
bytes32 private constant TYPEHASH =
13+
keccak256(
14+
"MintRequest(address to,address royaltyRecipient,uint256 royaltyBps,address primarySaleRecipient,string uri,uint256 quantity,uint256 price,address currency,uint128 validityStartTimestamp,uint128 validityEndTimestamp,bytes32 uid)"
15+
);
16+
17+
/// @dev Mapping from mint request UID => whether the mint request is processed.
18+
mapping(bytes32 => bool) private minted;
19+
20+
function __SignatureMintERC721_init() internal onlyInitializing {
21+
__EIP712_init("SignatureMintERC721", "1");
22+
}
23+
24+
function __SignatureMintERC721_init_unchained() internal onlyInitializing {}
25+
26+
/// @dev Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).
27+
function verify(MintRequest calldata _req, bytes calldata _signature)
28+
public
29+
view
30+
returns (bool success, address signer)
31+
{
32+
signer = _recoverAddress(_req, _signature);
33+
success = !minted[_req.uid] && _isAuthorizedSigner(signer);
34+
}
35+
36+
/// @dev Returns whether a given address is authorized to sign mint requests.
37+
function _isAuthorizedSigner(address _signer) internal view virtual returns (bool);
38+
39+
/// @dev Verifies a mint request and marks the request as minted.
40+
function _processRequest(MintRequest calldata _req, bytes calldata _signature)
41+
internal
42+
returns (address signer)
43+
{
44+
bool success;
45+
(success, signer) = verify(_req, _signature);
46+
47+
require(success, "Invalid request");
48+
require(
49+
_req.validityStartTimestamp <= block.timestamp && block.timestamp <= _req.validityEndTimestamp,
50+
"Request expired"
51+
);
52+
53+
minted[_req.uid] = true;
54+
}
55+
56+
/// @dev Returns the address of the signer of the mint request.
57+
function _recoverAddress(MintRequest calldata _req, bytes calldata _signature) internal view returns (address) {
58+
return _hashTypedDataV4(keccak256(_encodeRequest(_req))).recover(_signature);
59+
}
60+
61+
/// @dev Resolves 'stack too deep' error in `recoverAddress`.
62+
function _encodeRequest(MintRequest calldata _req) internal pure returns (bytes memory) {
63+
return
64+
abi.encode(
65+
TYPEHASH,
66+
_req.to,
67+
_req.royaltyRecipient,
68+
_req.royaltyBps,
69+
_req.primarySaleRecipient,
70+
keccak256(bytes(_req.uri)),
71+
_req.quantity,
72+
_req.pricePerToken,
73+
_req.currency,
74+
_req.validityStartTimestamp,
75+
_req.validityEndTimestamp,
76+
_req.uid
77+
);
78+
}
79+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# SignatureMintERC20Upgradeable
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
## Methods
12+
13+
### mintWithSignature
14+
15+
```solidity
16+
function mintWithSignature(ISignatureMintERC20.MintRequest req, bytes signature) external payable
17+
```
18+
19+
Mints tokens according to the provided mint request.
20+
21+
22+
23+
#### Parameters
24+
25+
| Name | Type | Description |
26+
|---|---|---|
27+
| req | ISignatureMintERC20.MintRequest | The payload / mint request.
28+
| signature | bytes | The signature produced by an account signing the mint request.
29+
30+
### verify
31+
32+
```solidity
33+
function verify(ISignatureMintERC20.MintRequest _req, bytes _signature) external view returns (bool success, address signer)
34+
```
35+
36+
37+
38+
*Verifies that a mint request is signed by an account holding MINTER_ROLE (at the time of the function call).*
39+
40+
#### Parameters
41+
42+
| Name | Type | Description |
43+
|---|---|---|
44+
| _req | ISignatureMintERC20.MintRequest | undefined
45+
| _signature | bytes | undefined
46+
47+
#### Returns
48+
49+
| Name | Type | Description |
50+
|---|---|---|
51+
| success | bool | undefined
52+
| signer | address | undefined
53+
54+
55+
56+
## Events
57+
58+
### TokensMintedWithSignature
59+
60+
```solidity
61+
event TokensMintedWithSignature(address indexed signer, address indexed mintedTo, ISignatureMintERC20.MintRequest mintRequest)
62+
```
63+
64+
65+
66+
67+
68+
#### Parameters
69+
70+
| Name | Type | Description |
71+
|---|---|---|
72+
| signer `indexed` | address | undefined |
73+
| mintedTo `indexed` | address | undefined |
74+
| mintRequest | ISignatureMintERC20.MintRequest | undefined |
75+
76+
77+

0 commit comments

Comments
 (0)