Skip to content

Commit 7c016c6

Browse files
authored
Add gasless support to airdrop contracts (#436)
* add gasless support to airdrop contracts * docs * v3.6.2
1 parent 4f35509 commit 7c016c6

11 files changed

+341
-38
lines changed

contracts/airdrop/AirdropERC1155.sol

+34-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@ import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
2121
// ========== Internal imports ==========
2222

2323
import "../interfaces/airdrop/IAirdropERC1155.sol";
24+
import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
2425

2526
// ========== Features ==========
2627
import "../extension/PermissionsEnumerable.sol";
28+
import "../extension/ContractMetadata.sol";
2729

2830
contract AirdropERC1155 is
2931
Initializable,
32+
ContractMetadata,
3033
PermissionsEnumerable,
3134
ReentrancyGuardUpgradeable,
35+
ERC2771ContextUpgradeable,
3236
MulticallUpgradeable,
3337
IAirdropERC1155
3438
{
@@ -46,7 +50,14 @@ contract AirdropERC1155 is
4650
constructor() initializer {}
4751

4852
/// @dev Initiliazes the contract, like a constructor.
49-
function initialize(address _defaultAdmin) external initializer {
53+
function initialize(
54+
address _defaultAdmin,
55+
string memory _contractURI,
56+
address[] memory _trustedForwarders
57+
) external initializer {
58+
__ERC2771Context_init_unchained(_trustedForwarders);
59+
60+
_setupContractURI(_contractURI);
5061
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
5162
__ReentrancyGuard_init();
5263
}
@@ -82,7 +93,9 @@ contract AirdropERC1155 is
8293
address _tokenAddress,
8394
address _tokenOwner,
8495
AirdropContent[] calldata _contents
85-
) external nonReentrant onlyRole(DEFAULT_ADMIN_ROLE) {
96+
) external nonReentrant {
97+
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Not authorized.");
98+
8699
uint256 len = _contents.length;
87100

88101
for (uint256 i = 0; i < len; ) {
@@ -116,4 +129,23 @@ contract AirdropERC1155 is
116129
}
117130
}
118131
}
132+
133+
/*///////////////////////////////////////////////////////////////
134+
Miscellaneous
135+
//////////////////////////////////////////////////////////////*/
136+
137+
/// @dev Checks whether contract metadata can be set in the given execution context.
138+
function _canSetContractURI() internal view override returns (bool) {
139+
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
140+
}
141+
142+
/// @dev See ERC2771
143+
function _msgSender() internal view virtual override returns (address sender) {
144+
return ERC2771ContextUpgradeable._msgSender();
145+
}
146+
147+
/// @dev See ERC2771
148+
function _msgData() internal view virtual override returns (bytes calldata) {
149+
return ERC2771ContextUpgradeable._msgData();
150+
}
119151
}

contracts/airdrop/AirdropERC20.sol

+30-2
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
2222
import "../interfaces/airdrop/IAirdropERC20.sol";
2323
import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol";
2424
import "../eip/interface/IERC20.sol";
25+
import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
2526

2627
// ========== Features ==========
2728
import "../extension/PermissionsEnumerable.sol";
29+
import "../extension/ContractMetadata.sol";
2830

2931
contract AirdropERC20 is
3032
Initializable,
33+
ContractMetadata,
3134
PermissionsEnumerable,
3235
ReentrancyGuardUpgradeable,
36+
ERC2771ContextUpgradeable,
3337
MulticallUpgradeable,
3438
IAirdropERC20
3539
{
@@ -47,7 +51,14 @@ contract AirdropERC20 is
4751
constructor() initializer {}
4852

4953
/// @dev Initiliazes the contract, like a constructor.
50-
function initialize(address _defaultAdmin) external initializer {
54+
function initialize(
55+
address _defaultAdmin,
56+
string memory _contractURI,
57+
address[] memory _trustedForwarders
58+
) external initializer {
59+
__ERC2771Context_init_unchained(_trustedForwarders);
60+
61+
_setupContractURI(_contractURI);
5162
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
5263
__ReentrancyGuard_init();
5364
}
@@ -83,7 +94,9 @@ contract AirdropERC20 is
8394
address _tokenAddress,
8495
address _tokenOwner,
8596
AirdropContent[] calldata _contents
86-
) external payable nonReentrant onlyRole(DEFAULT_ADMIN_ROLE) {
97+
) external payable nonReentrant {
98+
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Not authorized.");
99+
87100
uint256 len = _contents.length;
88101
uint256 nativeTokenAmount;
89102
uint256 refundAmount;
@@ -160,4 +173,19 @@ contract AirdropERC20 is
160173
}
161174
}
162175
}
176+
177+
/// @dev Checks whether contract metadata can be set in the given execution context.
178+
function _canSetContractURI() internal view override returns (bool) {
179+
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
180+
}
181+
182+
/// @dev See ERC2771
183+
function _msgSender() internal view virtual override returns (address sender) {
184+
return ERC2771ContextUpgradeable._msgSender();
185+
}
186+
187+
/// @dev See ERC2771
188+
function _msgData() internal view virtual override returns (bytes calldata) {
189+
return ERC2771ContextUpgradeable._msgData();
190+
}
163191
}

contracts/airdrop/AirdropERC721.sol

+34-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@ import "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
2121
// ========== Internal imports ==========
2222

2323
import "../interfaces/airdrop/IAirdropERC721.sol";
24+
import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
2425

2526
// ========== Features ==========
2627
import "../extension/PermissionsEnumerable.sol";
28+
import "../extension/ContractMetadata.sol";
2729

2830
contract AirdropERC721 is
2931
Initializable,
32+
ContractMetadata,
3033
PermissionsEnumerable,
3134
ReentrancyGuardUpgradeable,
35+
ERC2771ContextUpgradeable,
3236
MulticallUpgradeable,
3337
IAirdropERC721
3438
{
@@ -46,7 +50,14 @@ contract AirdropERC721 is
4650
constructor() initializer {}
4751

4852
/// @dev Initiliazes the contract, like a constructor.
49-
function initialize(address _defaultAdmin) external initializer {
53+
function initialize(
54+
address _defaultAdmin,
55+
string memory _contractURI,
56+
address[] memory _trustedForwarders
57+
) external initializer {
58+
__ERC2771Context_init_unchained(_trustedForwarders);
59+
60+
_setupContractURI(_contractURI);
5061
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
5162
__ReentrancyGuard_init();
5263
}
@@ -82,7 +93,9 @@ contract AirdropERC721 is
8293
address _tokenAddress,
8394
address _tokenOwner,
8495
AirdropContent[] calldata _contents
85-
) external nonReentrant onlyRole(DEFAULT_ADMIN_ROLE) {
96+
) external nonReentrant {
97+
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Not authorized.");
98+
8699
uint256 len = _contents.length;
87100

88101
for (uint256 i = 0; i < len; ) {
@@ -109,4 +122,23 @@ contract AirdropERC721 is
109122
}
110123
}
111124
}
125+
126+
/*///////////////////////////////////////////////////////////////
127+
Miscellaneous
128+
//////////////////////////////////////////////////////////////*/
129+
130+
/// @dev Checks whether contract metadata can be set in the given execution context.
131+
function _canSetContractURI() internal view override returns (bool) {
132+
return hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
133+
}
134+
135+
/// @dev See ERC2771
136+
function _msgSender() internal view virtual override returns (address sender) {
137+
return ERC2771ContextUpgradeable._msgSender();
138+
}
139+
140+
/// @dev See ERC2771
141+
function _msgData() internal view virtual override returns (bytes calldata) {
142+
return ERC2771ContextUpgradeable._msgData();
143+
}
112144
}

contracts/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@thirdweb-dev/contracts",
33
"description": "Collection of smart contracts deployable via the thirdweb SDK, dashboard and CLI",
4-
"version": "3.6.1",
4+
"version": "3.6.2",
55
"license": "Apache-2.0",
66
"repository": {
77
"type": "git",

docs/AirdropERC1155.md

+75-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ function contractType() external pure returns (bytes32)
6262
|---|---|---|
6363
| _0 | bytes32 | undefined |
6464

65+
### contractURI
66+
67+
```solidity
68+
function contractURI() external view returns (string)
69+
```
70+
71+
Returns the contract metadata URI.
72+
73+
74+
75+
76+
#### Returns
77+
78+
| Name | Type | Description |
79+
|---|---|---|
80+
| _0 | string | undefined |
81+
6582
### contractVersion
6683

6784
```solidity
@@ -212,7 +229,7 @@ Checks whether an account has a particular role; role restricti
212229
### initialize
213230

214231
```solidity
215-
function initialize(address _defaultAdmin) external nonpayable
232+
function initialize(address _defaultAdmin, string _contractURI, address[] _trustedForwarders) external nonpayable
216233
```
217234

218235

@@ -224,6 +241,30 @@ function initialize(address _defaultAdmin) external nonpayable
224241
| Name | Type | Description |
225242
|---|---|---|
226243
| _defaultAdmin | address | undefined |
244+
| _contractURI | string | undefined |
245+
| _trustedForwarders | address[] | undefined |
246+
247+
### isTrustedForwarder
248+
249+
```solidity
250+
function isTrustedForwarder(address forwarder) external view returns (bool)
251+
```
252+
253+
254+
255+
256+
257+
#### Parameters
258+
259+
| Name | Type | Description |
260+
|---|---|---|
261+
| forwarder | address | undefined |
262+
263+
#### Returns
264+
265+
| Name | Type | Description |
266+
|---|---|---|
267+
| _0 | bool | undefined |
227268

228269
### multicall
229270

@@ -281,6 +322,22 @@ Revokes role from an account.
281322
| role | bytes32 | keccak256 hash of the role. e.g. keccak256(&quot;TRANSFER_ROLE&quot;) |
282323
| account | address | Address of the account from which the role is being revoked. |
283324

325+
### setContractURI
326+
327+
```solidity
328+
function setContractURI(string _uri) external nonpayable
329+
```
330+
331+
Lets a contract admin set the URI for contract-level metadata.
332+
333+
*Caller should be authorized to setup contractURI, e.g. contract admin. See {_canSetContractURI}. Emits {ContractURIUpdated Event}.*
334+
335+
#### Parameters
336+
337+
| Name | Type | Description |
338+
|---|---|---|
339+
| _uri | string | keccak256 hash of the role. e.g. keccak256(&quot;TRANSFER_ROLE&quot;) |
340+
284341

285342

286343
## Events
@@ -305,6 +362,23 @@ Emitted when an airdrop fails for a recipient address.
305362
| tokenId | uint256 | undefined |
306363
| amount | uint256 | undefined |
307364

365+
### ContractURIUpdated
366+
367+
```solidity
368+
event ContractURIUpdated(string prevURI, string newURI)
369+
```
370+
371+
372+
373+
374+
375+
#### Parameters
376+
377+
| Name | Type | Description |
378+
|---|---|---|
379+
| prevURI | string | undefined |
380+
| newURI | string | undefined |
381+
308382
### Initialized
309383

310384
```solidity

0 commit comments

Comments
 (0)