Skip to content

Commit 9e525bc

Browse files
committed
update Drop design doc
1 parent 2a24a3c commit 9e525bc

File tree

1 file changed

+33
-30
lines changed

1 file changed

+33
-30
lines changed

contracts/drop/drop.md

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ struct ClaimCondition {
4040
uint256 startTimestamp;
4141
uint256 maxClaimableSupply;
4242
uint256 supplyClaimed;
43-
uint256 quantityLimitPerTransaction;
44-
uint256 waitTimeInSecondsBetweenClaims;
43+
uint256 quantityLimitPerWallet;
4544
bytes32 merkleRoot;
4645
uint256 pricePerToken;
4746
address currency;
@@ -53,19 +52,17 @@ struct ClaimCondition {
5352
| startTimestamp | uint256 | The unix timestamp after which the claim condition applies. The same claim condition applies until the startTimestamp of the next claim condition. |
5453
| maxClaimableSupply | uint256 | The maximum total number of tokens that can be claimed under the claim condition. |
5554
| supplyClaimed | uint256 | At any given point, the number of tokens that have been claimed under the claim condition. |
56-
| quantityLimitPerTransaction | uint256 | The maximum number of tokens that can be claimed in a single transaction. |
57-
| waitTimeInSecondsBetweenClaims | uint256 | The least number of seconds an account must wait after claiming tokens, to be able to claim tokens again. |
55+
| quantityLimitPerWallet | uint256 | The maximum number of tokens that can be claimed by a wallet under a given ClaimCondition. |
5856
| merkleRoot | bytes32 | The allowlist of addresses that can claim tokens under the claim condition.
5957

60-
(Optional) The allowlist may specify the exact amount of tokens that an address in the allowlist is eligible to claim.
58+
(Optional) The allowlist may specify quantity limits, price and currency for addresses in the list, overriding these values under that claim condition.
6159

6260
The parameters that make up a claim condition can be composed in different ways to create specific restrictions around a mint. For example, a single claim condition where:
6361

64-
- `quantityLimitPerTransaction = 5`
65-
- `waitTimeInSecondsBetweenClaims = type(uint256).max`
62+
- `quantityLimitPerWallet = 5`
6663
- `merkleRoot = bytes32(0)`
6764

68-
creates restrictions around a mint, where (1) any wallet can participate in the mint, (2) a wallet can mint at most 5 tokens and (3) a wallet can claim tokens only once.
65+
creates restrictions around a mint, where (1) a wallet can mint at most 5 tokens and (2) all wallets are subject to general claim condition limits, without any overrides.
6966

7067
A `Drop` contract lets a contract admin establish a series of claim conditions, at once. Since each claim condition specifies a `startTime`, a contract admin can establish a series of claim conditions, ordered by their start time, to specify different set of restrictions around minting, during different periods of time.
7168

@@ -77,43 +74,51 @@ A `Drop` contract natively keeps track of claim conditions set by a contract adm
7774
struct ClaimConditionList {
7875
uint256 currentStartId;
7976
uint256 count;
80-
mapping(uint256 => ClaimCondition) phases;
81-
mapping(uint256 => mapping(address => uint256)) limitLastClaimTimestamp;
82-
mapping(uint256 => BitMapsUpgradeable.BitMap) limitMerkleProofClaim;
77+
mapping(uint256 => ClaimCondition) conditions;
78+
mapping(uint256 => mapping(address => uint256)) supplyClaimedByWallet;
8379
}
8480
```
8581

8682
| Parameter | Description |
8783
| --- | --- |
8884
| currentStartId | The uid for the first claim condition amongst the current set of claim conditions. The uid for each next claim condition is one more than the previous claim condition's uid. |
89-
| count | The total number of phases / claim conditions in the list of claim conditions. |
90-
| phases | The claim conditions at a given uid. Claim conditions are ordered in an ascending order by their startTimestamp. |
91-
| limitLastClaimTimestamp | Map from an account and uid for a claim condition, to the last timestamp at which the account claimed tokens under that claim condition. |
92-
| limitMerkleProofClaim | Map from a claim condition uid to whether an address in an allowlist has already claimed tokens i.e. used their place in the allowlist. |
85+
| count | The total number of claim conditions in the list of claim conditions. |
86+
| conditions | The claim conditions at a given uid. Claim conditions are ordered in an ascending order by their startTimestamp. |
87+
| supplyClaimedByWallet | Map from a claim condition uid and account to the supply claimed by that account. |
88+
89+
### Allowlist as an override list
90+
91+
As mentioned above, an allowlist can specify different conditions for addresses in the list. This way, it serves as an override over general/open claim condition values for non-allowlisted addresses.
92+
In this allowlist or override-list, an admin can set any/all of these three:
93+
94+
- quantity limit
95+
- price
96+
- currency
97+
98+
If a value is not set for any of these, then the value specified in general claim condition will be used. However, currency override will be considered only when a price override is set too, and not without it.
9399

94100
### Setting claim conditions
95101

96102
In all `Drop` contracts, a contract admin specifies the following when setting claim conditions:
97103

98104
| Parameter | Type | Description |
99105
| --- | --- | --- |
100-
| phases | ClaimCondition[] | Claim conditions in ascending order by startTimestamp. |
101-
| resetClaimEligibility | bool | Whether to reset limitLastClaimTimestamp and limitMerkleProofClaim values when setting new claim conditions. |
106+
| conditions | ClaimCondition[] | Claim conditions in ascending order by `startTimestamp`. |
107+
| resetClaimEligibility | bool | Whether to reset `supplyClaimedByWallet` values when setting new claim conditions. |
102108

103-
When setting claim conditions, any existing set of claim conditions stored in `ClaimConditionsList` are overwritten with the new claim conditions specified in `phases`.
109+
When setting claim conditions, any existing set of claim conditions stored in `ClaimConditionsList` are overwritten with the new claim conditions specified in `conditions`.
104110

105-
The claim conditions specified in `phases` are expected to be in ordered in ascending order, by their ‘start time’. As a result, only one claim condition is active during at any given time.
111+
The claim conditions specified in `conditions` are expected to be in ordered in ascending order, by their ‘start time’. As a result, only one claim condition is active during at any given time.
106112

107-
Each of the claim conditions specified in `phases` is assigned a unique integer ID. The UID of the first condition in `phases` is stored as the `ClaimConditionList.currentStartId` and each next claim condition’s UID is one more than the previous condition’s UID.
113+
Each of the claim conditions specified in `conditions` is assigned a unique integer ID. The UID of the first condition in `conditions` is stored as the `ClaimConditionList.currentStartId` and each next claim condition’s UID is one more than the previous condition’s UID.
108114

109115
![claim-conditions-diagram-1.png](/assets/claim-conditions-diagram-1.png)
110116

111-
The `resetClaimEligibility` boolean flag determines what UIDs are assigned to the claim conditions specified in `phases`. Since `ClaimConditionList.limitLastClaimTimestamp` and `ClaimConditionList.limitMerkleProofClaim` are both indexed by the UID of claim conditions, this gives a contract admin more granular control over the restrictions that claim conditions can express. We now illustrate this with an example:
117+
The `resetClaimEligibility` boolean flag determines what UIDs are assigned to the claim conditions specified in `conditions`. Since `ClaimConditionList.supplyClaimedByWallet` is indexed by the UID of claim conditions, this gives a contract admin more granular control over the restrictions that claim conditions can express. We now illustrate this with an example:
112118

113119
Let’s say an existing claim condition **C1** specifies the following restrictions:
114120

115-
- `quantityLimitPerTransaction = 1`
116-
- `waitTimeInSecondsBetweenClaims = type(uint256).max`
121+
- `quantityLimitPerWallet = 1`
117122
- `merkleRoot = bytes32(0)`
118123
- `pricePerToken = 0.1 ether`
119124
- `currency = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` (i.e. native token of the chain e.g ether for Ethereum mainnet)
@@ -122,20 +127,18 @@ At a high level, **C1** expresses the following restrictions on minting — any
122127

123128
Let’s say the contract admin wants to increase the price per token from 0.1 ether to 0.2 ether, while ensuring that wallets that have already claimed tokens are not able to claim tokens again. Essentially, the contract admin now wants to instantiate a claim condition **C2** with the following restrictions:
124129

125-
- `quantityLimitPerTransaction = 1`
126-
- `waitTimeInSecondsBetweenClaims = type(uint256).max`
130+
- `quantityLimitPerWallet = 1`
127131
- `merkleRoot = bytes32(0)`
128132
- `pricePerToken = 0.2 ether`
129133
- `currency = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` (i.e. native token of the chain e.g ether for Ethereum mainnet)
130134

131-
To go from **C1** to **C2** while ensuring that wallets that have already claimed tokens are not able to claim tokens again, the contract admin will set claim conditions while specifying `resetClaimEligibility == false`. As a result, the **C2** will be assigned the same UID as **C1**. Since `ClaimConditionList.limitLastClaimTimestamp` is indexed by the UID of claim conditions, the information of the timestamp at which a wallet claimed tokens during **C1** will not be lost. And so, wallets that claimed tokens during **C1** will now be ineligible to claim tokens during **C2** since the following check will always fail:
135+
To go from **C1** to **C2** while ensuring that wallets that have already claimed tokens are not able to claim tokens again, the contract admin will set claim conditions while specifying `resetClaimEligibility == false`. As a result, the **C2** will be assigned the same UID as **C1**. Since `ClaimConditionList.supplyClaimedByWallet` is indexed by the UID of claim conditions, the information of the quantity of tokens claimed by the wallet during **C1** will not be lost. And so, wallets that claimed tokens during **C1** will now be ineligible to claim tokens during **C2** because of the following check:
132136

133137
```solidity
134138
// pseudo-code
135-
nextValidClaimTimestamp =
136-
limitLastClaimTimestamp[UID_of_C2][claimer_address] + C2.waitTimeInSecondsBetweenClaims
139+
supplyClaimedByWallet = claimCondition.supplyClaimedByWallet[conditionId][claimer];
137140
138-
require(block.timestamp >= nextValidClaimTimestamp);
141+
require(quantityToClaim + supplyClaimedByWallet <= quantityLimitPerWallet);
139142
```
140143

141144
### EIPs supported / implemented
@@ -151,7 +154,7 @@ There are a few key differences between the three implementations —
151154

152155
The distribution mechanism of thirdweb’s `Drop` contracts is vulnerable to [sybil attacks](https://en.wikipedia.org/wiki/Sybil_attack). That is, despite the various ways in which restrictions can be applied to the minting of tokens, some restrictions that claim conditions can express target wallets and not persons.
153156

154-
For example, the restriction `waitTimeInSecondsBetweenClaims` expresses the least amount of time a *wallet* must wait, before claiming tokens again during the respective claim condition. A sophisticated actor may generate multiple wallets to claim tokens in a way that undermine such restrictions, when viewing such restrictions as restrictions on unique persons, and not wallets.
157+
For example, the restriction `quantityLimitPerWallet` expresses the max quantity a *wallet* can claim during the respective claim condition. A sophisticated actor may generate multiple wallets to claim tokens in a way that undermine such restrictions, when viewing such restrictions as restrictions on unique persons, and not wallets.
155158

156159
## Authors
157160
- [nkrishang](https://github.com/nkrishang)

0 commit comments

Comments
 (0)