Skip to content

Commit 49744dd

Browse files
authored
Zero pack transfer fix (#238)
* set bundle to private; use PermissionsEnumerable; * v3.1.6-1 * zero pack transfer shouldn't toggle canUpdatePack * fix forwarder * bump version 1 -> 2
1 parent 5c02595 commit 49744dd

File tree

10 files changed

+79
-122
lines changed

10 files changed

+79
-122
lines changed

contracts/extension/TokenBundle.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface IERC165 {
1717

1818
abstract contract TokenBundle is ITokenBundle {
1919
/// @dev Mapping from bundle UID => bundle info.
20-
mapping(uint256 => BundleInfo) public bundle;
20+
mapping(uint256 => BundleInfo) private bundle;
2121

2222
/// @dev Returns the total number of assets in a particular bundle.
2323
function getTokenCountOfBundle(uint256 _bundleId) public view returns (uint256) {

contracts/openzeppelin-presets/metatx/MinimalForwarderEOAOnly.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ contract MinimalForwarderEOAOnly is EIP712 {
2626

2727
mapping(address => uint256) private _nonces;
2828

29-
constructor() EIP712("MinimalForwarderEOAOnly", "0.0.1") {}
29+
constructor() EIP712("GSNv2 Forwarder", "0.0.1") {}
3030

3131
function getNonce(address from) public view returns (uint256) {
3232
return _nonces[from];

contracts/pack/Pack.sol

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ import "../openzeppelin-presets/metatx/ERC2771ContextUpgradeable.sol";
2222
import "../extension/ContractMetadata.sol";
2323
import "../extension/Royalty.sol";
2424
import "../extension/Ownable.sol";
25-
import "../extension/Permissions.sol";
25+
import "../extension/PermissionsEnumerable.sol";
2626
import { TokenStore, ERC1155Receiver } from "../extension/TokenStore.sol";
2727

2828
contract Pack is
2929
Initializable,
3030
ContractMetadata,
3131
Ownable,
3232
Royalty,
33-
Permissions,
33+
PermissionsEnumerable,
3434
TokenStore,
3535
ReentrancyGuardUpgradeable,
3636
ERC2771ContextUpgradeable,
@@ -43,7 +43,7 @@ contract Pack is
4343
//////////////////////////////////////////////////////////////*/
4444

4545
bytes32 private constant MODULE_TYPE = bytes32("Pack");
46-
uint256 private constant VERSION = 1;
46+
uint256 private constant VERSION = 2;
4747

4848
address private immutable forwarder;
4949

@@ -433,7 +433,7 @@ contract Pack is
433433
} else {
434434
for (uint256 i = 0; i < ids.length; ++i) {
435435
// pack can no longer be updated after first transfer to non-zero address
436-
if (canUpdatePack[ids[i]]) {
436+
if (canUpdatePack[ids[i]] && amounts[i] != 0) {
437437
canUpdatePack[ids[i]] = false;
438438
}
439439
}

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.1.6-0",
4+
"version": "3.1.6-1",
55
"license": "Apache-2.0",
66
"repository": {
77
"type": "git",

docs/ERC721Multiwrap.md

-23
Original file line numberDiff line numberDiff line change
@@ -83,29 +83,6 @@ function balanceOf(address owner) external view returns (uint256)
8383
|---|---|---|
8484
| _0 | uint256 | undefined |
8585

86-
### bundle
87-
88-
```solidity
89-
function bundle(uint256) external view returns (uint256 count, string uri)
90-
```
91-
92-
93-
94-
95-
96-
#### Parameters
97-
98-
| Name | Type | Description |
99-
|---|---|---|
100-
| _0 | uint256 | undefined |
101-
102-
#### Returns
103-
104-
| Name | Type | Description |
105-
|---|---|---|
106-
| count | uint256 | undefined |
107-
| uri | string | undefined |
108-
10986
### contractURI
11087

11188
```solidity

docs/Multiwrap.md

-23
Original file line numberDiff line numberDiff line change
@@ -66,29 +66,6 @@ function balanceOf(address owner) external view returns (uint256)
6666
|---|---|---|
6767
| _0 | uint256 | undefined |
6868

69-
### bundle
70-
71-
```solidity
72-
function bundle(uint256) external view returns (uint256 count, string uri)
73-
```
74-
75-
76-
77-
78-
79-
#### Parameters
80-
81-
| Name | Type | Description |
82-
|---|---|---|
83-
| _0 | uint256 | undefined |
84-
85-
#### Returns
86-
87-
| Name | Type | Description |
88-
|---|---|---|
89-
| count | uint256 | undefined |
90-
| uri | string | undefined |
91-
9269
### contractType
9370

9471
```solidity

docs/Pack.md

+45-23
Original file line numberDiff line numberDiff line change
@@ -99,29 +99,6 @@ function balanceOfBatch(address[] accounts, uint256[] ids) external view returns
9999
|---|---|---|
100100
| _0 | uint256[] | undefined |
101101

102-
### bundle
103-
104-
```solidity
105-
function bundle(uint256) external view returns (uint256 count, string uri)
106-
```
107-
108-
109-
110-
111-
112-
#### Parameters
113-
114-
| Name | Type | Description |
115-
|---|---|---|
116-
| _0 | uint256 | undefined |
117-
118-
#### Returns
119-
120-
| Name | Type | Description |
121-
|---|---|---|
122-
| count | uint256 | undefined |
123-
| uri | string | undefined |
124-
125102
### canUpdatePack
126103

127104
```solidity
@@ -286,6 +263,51 @@ Returns the admin role that controls the specified role.
286263
|---|---|---|
287264
| _0 | bytes32 | undefined |
288265

266+
### getRoleMember
267+
268+
```solidity
269+
function getRoleMember(bytes32 role, uint256 index) external view returns (address member)
270+
```
271+
272+
Returns the role-member from a list of members for a role, at a given index.
273+
274+
*Returns `member` who has `role`, at `index` of role-members list. See struct {RoleMembers}, and mapping {roleMembers}*
275+
276+
#### Parameters
277+
278+
| Name | Type | Description |
279+
|---|---|---|
280+
| role | bytes32 | keccak256 hash of the role. e.g. keccak256(&quot;TRANSFER_ROLE&quot;) |
281+
| index | uint256 | Index in list of current members for the role. |
282+
283+
#### Returns
284+
285+
| Name | Type | Description |
286+
|---|---|---|
287+
| member | address | Address of account that has `role` |
288+
289+
### getRoleMemberCount
290+
291+
```solidity
292+
function getRoleMemberCount(bytes32 role) external view returns (uint256 count)
293+
```
294+
295+
Returns total number of accounts that have a role.
296+
297+
*Returns `count` of accounts that have `role`. See struct {RoleMembers}, and mapping {roleMembers}*
298+
299+
#### Parameters
300+
301+
| Name | Type | Description |
302+
|---|---|---|
303+
| role | bytes32 | keccak256 hash of the role. e.g. keccak256(&quot;TRANSFER_ROLE&quot;) |
304+
305+
#### Returns
306+
307+
| Name | Type | Description |
308+
|---|---|---|
309+
| count | uint256 | Total number of accounts that have `role` |
310+
289311
### getRoyaltyInfoForToken
290312

291313
```solidity

docs/TokenBundle.md

-23
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,6 @@
1010

1111
## Methods
1212

13-
### bundle
14-
15-
```solidity
16-
function bundle(uint256) external view returns (uint256 count, string uri)
17-
```
18-
19-
20-
21-
*Mapping from bundle UID =&gt; bundle info.*
22-
23-
#### Parameters
24-
25-
| Name | Type | Description |
26-
|---|---|---|
27-
| _0 | uint256 | undefined |
28-
29-
#### Returns
30-
31-
| Name | Type | Description |
32-
|---|---|---|
33-
| count | uint256 | undefined |
34-
| uri | string | undefined |
35-
3613
### getTokenCountOfBundle
3714

3815
```solidity

docs/TokenStore.md

-23
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,6 @@
1010

1111
## Methods
1212

13-
### bundle
14-
15-
```solidity
16-
function bundle(uint256) external view returns (uint256 count, string uri)
17-
```
18-
19-
20-
21-
22-
23-
#### Parameters
24-
25-
| Name | Type | Description |
26-
|---|---|---|
27-
| _0 | uint256 | undefined |
28-
29-
#### Returns
30-
31-
| Name | Type | Description |
32-
|---|---|---|
33-
| count | uint256 | undefined |
34-
| uri | string | undefined |
35-
3613
### getTokenCountOfBundle
3714

3815
```solidity

src/test/Pack.t.sol

+27
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,33 @@ contract PackTest is BaseTest {
173173
pack.grantRole(keccak256("MINTER_ROLE"), address(tokenOwner));
174174
}
175175

176+
/*///////////////////////////////////////////////////////////////
177+
Unit tests: Miscellaneous
178+
//////////////////////////////////////////////////////////////*/
179+
180+
function test_revert_addPackContents_RandomAccountGrief() public {
181+
uint256 packId = pack.nextTokenIdToMint();
182+
address recipient = address(1);
183+
184+
vm.prank(address(tokenOwner));
185+
pack.createPack(packContents, numOfRewardUnits, packUri, 0, 1, recipient);
186+
187+
// random address tries to transfer zero amount
188+
address randomAccount = address(0x123);
189+
vm.prank(randomAccount);
190+
pack.safeTransferFrom(randomAccount, address(567), packId, 0, ""); // zero transfer
191+
192+
// canUpdatePack should remain true, since no packs were transferred
193+
assertTrue(pack.canUpdatePack(packId));
194+
195+
erc20.mint(address(tokenOwner), 1000 ether);
196+
erc1155.mint(address(tokenOwner), 2, 200);
197+
198+
vm.prank(address(tokenOwner));
199+
// Should not revert
200+
pack.addPackContents(packId, additionalContents, additionalContentsRewardUnits, recipient);
201+
}
202+
176203
/*///////////////////////////////////////////////////////////////
177204
Unit tests: `createPack`
178205
//////////////////////////////////////////////////////////////*/

0 commit comments

Comments
 (0)