-
Notifications
You must be signed in to change notification settings - Fork 5
/
Taxation.sol
428 lines (368 loc) · 12.7 KB
/
Taxation.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// contracts/token/modules/interfaces/Taxation.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
import "./interfaces/ITaxation.sol";
import "./Valuation.sol";
import "./ERC721.sol";
import "./Remittance.sol";
import "./Beneficiary.sol";
abstract contract Taxation is
ITaxation,
ERC721,
Valuation,
Remittance,
Beneficiary
{
//////////////////////////////
/// State
//////////////////////////////
/// @notice Mapping from token ID to taxation collected over lifetime in Wei.
mapping(uint256 => uint256) public taxationCollected;
/// @notice Mapping from token ID to taxation collected since last transfer in Wei.
mapping(uint256 => uint256) private _taxCollectedSinceLastTransfer;
/// @notice Percentage taxation rate. e.g. 5% or 100%
/// @dev Granular to an additionial 10 zeroes.
/// e.g. 100% => 1000000000000
/// e.g. 5% => 50000000000
mapping(uint256 => uint256) internal _taxNumerators;
uint256 private constant TAX_DENOMINATOR = 1000000000000;
/// @notice Over what period, in days, should taxation be applied?
mapping(uint256 => uint256) internal _collectionFrequencies;
/// @notice Mapping from token ID to Unix timestamp when last tax collection occured.
/// @dev This is used to determine how much time has passed since last collection and the present
/// and resultingly how much tax is due in the present.
/// @dev In the event that a foreclosure happens AFTER it should have, this
/// variable is backdated to when it should've occurred. Thus: `_chainOfTitle` is
/// accurate to the actual possession period.
mapping(uint256 => uint256) private _lastCollectionTimes;
/// @notice Mapping from token ID to funds for paying tax ("Deposit") in Wei.
mapping(uint256 => uint256) private _deposits;
//////////////////////////////
/// Events
//////////////////////////////
/// @notice Alert token foreclosed.
/// @param tokenId ID of token.
/// @param prevOwner Address of previous owner.
event LogForeclosure(uint256 indexed tokenId, address indexed prevOwner);
/// @notice Alert tax collected.
/// @param tokenId ID of token.
/// @param collected Amount in wei.
event LogCollection(uint256 indexed tokenId, uint256 indexed collected);
//////////////////////////////
/// Modifiers
//////////////////////////////
/// @notice Envokes tax collection.
/// @dev Tax collection is triggered by an external envocation of a method wrapped by
/// this modifier.
/// @param tokenId_ ID of token to collect tax for.
modifier _collectTax(uint256 tokenId_) {
collectTax(tokenId_);
_;
}
//////////////////////////////
/// Public Methods
//////////////////////////////
/// @notice Collects tax.
/// @param tokenId_ ID of token to collect tax for.
/// @dev Strictly envoked by modifier but can be called publically.
function collectTax(uint256 tokenId_) public {
uint256 valuation = valuationOf(tokenId_);
// There's no tax to be collected on an unvalued token.
if (valuation == 0) return;
// If valuation > 0, contract has not foreclosed.
uint256 owed = _taxOwed(tokenId_);
// Owed will be 0 when the token is owned by its beneficiary.
// i.e. no tax is owed.
if (owed == 0) return;
// If foreclosure should have occured in the past, last collection time will be
// backdated to when the tax was last paid for.
if (foreclosed(tokenId_)) {
_setLastCollectionTime(tokenId_, _backdatedForeclosureTime(tokenId_));
// Set remaining deposit to be collected.
owed = depositOf(tokenId_);
} else {
_setLastCollectionTime(tokenId_, block.timestamp);
}
// Normal collection
_setDeposit(tokenId_, depositOf(tokenId_) - owed);
taxationCollected[tokenId_] += owed;
_setTaxCollectedSinceLastTransfer(
tokenId_,
taxCollectedSinceLastTransferOf(tokenId_) + owed
);
emit LogCollection(tokenId_, owed);
/// Remit taxation to beneficiary.
_remit(beneficiaryOf(tokenId_), owed, RemittanceTriggers.TaxCollection);
_forecloseIfNecessary(tokenId_);
}
/// @dev See {ITaxation.deposit}
function deposit(uint256 tokenId_)
public
payable
override
_onlyApprovedOrOwner(tokenId_)
_collectTax(tokenId_)
{
_setDeposit(tokenId_, depositOf(tokenId_) + msg.value);
}
/// @dev See {ITaxation.withdrawDeposit}
function withdrawDeposit(uint256 tokenId_, uint256 wei_)
public
override
_onlyApprovedOrOwner(tokenId_)
_collectTax(tokenId_)
{
_withdrawDeposit(tokenId_, wei_);
}
/// @dev See {ITaxation.exit}
function exit(uint256 tokenId_)
public
override
_onlyApprovedOrOwner(tokenId_)
_collectTax(tokenId_)
{
_withdrawDeposit(tokenId_, depositOf(tokenId_));
}
//////////////////////////////
/// Public Getters
//////////////////////////////
/// @dev See {ITaxation.taxCollectedSinceLastTransferOf}
function taxCollectedSinceLastTransferOf(uint256 tokenId_)
public
view
override
_tokenMinted(tokenId_)
returns (uint256)
{
return _taxCollectedSinceLastTransfer[tokenId_];
}
/// @dev See {ITaxation.taxRateOf}
function taxRateOf(uint256 tokenId_)
public
view
override
_tokenMinted(tokenId_)
returns (uint256)
{
return _taxNumerators[tokenId_];
}
/// @dev See {ITaxation.collectionFrequencyOf}
function collectionFrequencyOf(uint256 tokenId_)
public
view
override
_tokenMinted(tokenId_)
returns (uint256)
{
return _collectionFrequencies[tokenId_];
}
/// @dev See {ITaxation.taxOwedSince}
function taxOwedSince(uint256 tokenId_, uint256 time_)
public
view
override
_tokenMinted(tokenId_)
returns (uint256 taxDue)
{
uint256 valuation = valuationOf(tokenId_);
return
(((valuation * time_) / collectionFrequencyOf(tokenId_)) *
taxRateOf(tokenId_)) / TAX_DENOMINATOR;
}
/// @dev See {ITaxation.taxOwed}
function taxOwed(uint256 tokenId_)
public
view
override
returns (uint256 amount, uint256 timestamp)
{
return (_taxOwed(tokenId_), block.timestamp);
}
/// @dev See {ITaxation.lastCollectionTimeOf}
function lastCollectionTimeOf(uint256 tokenId_)
public
view
override
returns (uint256)
{
return _lastCollectionTimes[tokenId_];
}
/// @dev See {ITaxation.depositOf}
function depositOf(uint256 tokenId_)
public
view
override
_tokenMinted(tokenId_)
returns (uint256)
{
return _deposits[tokenId_];
}
/// @dev See {ITaxation.withdrawableDeposit}
function withdrawableDeposit(uint256 tokenId_)
public
view
override
returns (uint256)
{
if (foreclosed(tokenId_)) {
return 0;
} else {
return depositOf(tokenId_) - _taxOwed(tokenId_);
}
}
/// @dev See {ITaxation.foreclosed}
function foreclosed(uint256 tokenId_) public view override returns (bool) {
uint256 owed = _taxOwed(tokenId_);
if (owed >= depositOf(tokenId_)) {
return true;
} else {
return false;
}
}
/// @dev See {ITaxation.foreclosureTime}
function foreclosureTime(uint256 tokenId_)
public
view
override
returns (uint256)
{
uint256 taxPerSecond = taxOwedSince(tokenId_, 1);
uint256 withdrawable = withdrawableDeposit(tokenId_);
if (withdrawable > 0) {
// Time until deposited surplus no longer surpasses amount owed.
return block.timestamp + withdrawable / taxPerSecond;
} else if (taxPerSecond > 0) {
// Token is active but in foreclosed state.
// Returns when foreclosure should have occured i.e. when tax owed > deposits.
return _backdatedForeclosureTime(tokenId_);
} else {
// Actively foreclosed (valuation is 0)
return lastCollectionTimeOf(tokenId_);
}
}
//////////////////////////////
/// Internal Methods
//////////////////////////////
/// @notice Forecloses if no deposit for a given token.
/// @param tokenId_ ID of token to potentially foreclose.
function _forecloseIfNecessary(uint256 tokenId_) internal {
// If there are not enough funds to cover the entire amount owed, `__collectTax`
// will take whatever's left of the deposit, resulting in a zero balance.
if (depositOf(tokenId_) == 0) {
// Unset the valuation
_setValuation(tokenId_, 0);
// Become steward of asset (aka foreclose)
address currentOwner = ownerOf(tokenId_);
_transfer(currentOwner, address(this), tokenId_);
emit LogForeclosure(tokenId_, currentOwner);
}
}
/// @notice Withdraws deposit back to its owner.
/// @dev Parent callers must enforce `ownerOnly(tokenId_)`.
/// @param tokenId_ ID of token to withdraw deposit for.
/// @param wei_ Amount of Wei to withdraw.
function _withdrawDeposit(uint256 tokenId_, uint256 wei_) internal {
// If triggered with no wei, return.
if (wei_ == 0) return;
// Note: Can withdraw whole deposit, which immediately triggers foreclosure.
require(wei_ <= depositOf(tokenId_), "Cannot withdraw more than deposited");
address currentOwner = ownerOf(tokenId_);
require(currentOwner != address(this), "Cannot withdraw deposit to self");
_setDeposit(tokenId_, depositOf(tokenId_) - wei_);
_remit(currentOwner, wei_, RemittanceTriggers.WithdrawnDeposit);
_forecloseIfNecessary(tokenId_);
}
/// @notice Collect Tax
function _beforeTokenTransfer(
address from_,
address to_,
uint256 tokenId_
) internal virtual override(ERC721) {
collectTax(tokenId_);
super._beforeTokenTransfer(from_, to_, tokenId_);
}
/// @notice Reset tax collected
function _afterTokenTransfer(
address from_,
address to_,
uint256 tokenId_
) internal virtual override(ERC721) {
_setTaxCollectedSinceLastTransfer(tokenId_, 0);
super._afterTokenTransfer(from_, to_, tokenId_);
}
//////////////////////////////
/// Internal Setters
//////////////////////////////
/// @notice Sets tax collected since last transfer.
/// @param tokenId_ ID of token.
/// @param amount_ Amount in Wei.
function _setTaxCollectedSinceLastTransfer(uint256 tokenId_, uint256 amount_)
internal
{
_taxCollectedSinceLastTransfer[tokenId_] = amount_;
}
/// @notice Sets last collection time for a given token.
/// @param tokenId_ ID of token.
/// @param collectionTime_ Timestamp.
function _setLastCollectionTime(uint256 tokenId_, uint256 collectionTime_)
internal
_tokenMinted(tokenId_)
{
_lastCollectionTimes[tokenId_] = collectionTime_;
}
/// @notice Internal tax rate setter.
/// @dev Should be invoked immediately after calling `#_safeMint`
/// @param tokenId_ Token to set
/// @param rate_ The taxation rate up to 10 decimal places. See `_taxNumerators` declaration.
function _setTaxRate(uint256 tokenId_, uint256 rate_)
internal
_tokenMinted(tokenId_)
{
_taxNumerators[tokenId_] = rate_;
}
/// @notice Internal period setter.
/// @dev Should be invoked immediately after calling `#_safeMint`
/// @param tokenId_ Token to set
/// @param days_ How many days are between subsequent tax collections?
function _setCollectionFrequency(uint256 tokenId_, uint256 days_)
internal
_tokenMinted(tokenId_)
{
_collectionFrequencies[tokenId_] = days_ * 1 days;
}
/// @notice Sets deposit for a given token.
/// @param tokenId_ ID of token.
/// @param amount_ New deposit amount.
function _setDeposit(uint256 tokenId_, uint256 amount_) internal {
_deposits[tokenId_] = amount_;
}
//////////////////////////////
/// Internal Getters
//////////////////////////////
/// @notice How much is owed from the last collection until now?
/// @param tokenId_ ID of token requesting amount for.
/// @return Tax Due in wei
function _taxOwed(uint256 tokenId_) internal view returns (uint256) {
// If the token is owned by its beneficiary, nothing is owed.
// (e.g. beneficiary wrapped a token).
if (ownerOf(tokenId_) == beneficiaryOf(tokenId_)) return 0;
uint256 timeElapsed = block.timestamp - _lastCollectionTimes[tokenId_];
return taxOwedSince(tokenId_, timeElapsed);
}
/// @notice Returns the time when tax owed initially exceeded deposits.
/// @dev last collected time + ((time_elapsed * deposit) / owed)
/// @dev Returns within +/- 2s of previous values due to Solidity rounding
/// down integer division without regard for significant digits, which produces
/// variable results e.g. `599.9999999999851` becomes `599`.
/// @param tokenId_ ID of token requesting
/// @return Unix timestamp
function _backdatedForeclosureTime(uint256 tokenId_)
internal
view
returns (uint256)
{
uint256 last = lastCollectionTimeOf(tokenId_);
uint256 timeElapsed = block.timestamp - last;
return last + ((timeElapsed * depositOf(tokenId_)) / _taxOwed(tokenId_));
}
}