Skip to content

Commit 9bb26a0

Browse files
authored
Add CL4RRedeemer (#791)
* Add CL4RRedeemer * lint * Clean unused vars * Fix * Fix the test * More coverage * lint * Add description * Fix description
1 parent ab316cc commit 9bb26a0

File tree

3 files changed

+554
-0
lines changed

3 files changed

+554
-0
lines changed

contracts/schemes/CL4RRedeemer.sol

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
pragma solidity ^0.6.12;
2+
// SPDX-License-Identifier: GPL-3.0
3+
4+
import "./ContinuousLocking4Reputation.sol";
5+
6+
/**
7+
* @title A scheme for redeeming a ContinuousLocking4Reputation contract used in a different DAO.
8+
* This contract can be used to migrate from an older DAO to a new one while the older DAO
9+
* has an active ContinuousLocking4Reputation.
10+
* Using it should be done by initializing this contract as a scheme in the new DAO,
11+
* with the old ContinuousLocking4Reputation as an init parameter (_ct4r).
12+
* Note: the old ContinuousLocking4Reputation should be unregistered as a scheme from the older DAO so
13+
* that redeeming is done only through this scheme into the new DAO.
14+
*/
15+
contract CL4RRedeemer is ArcScheme {
16+
using SafeMath for uint256;
17+
using SafeERC20 for IERC20;
18+
using RealMath for uint216;
19+
using RealMath for uint256;
20+
using Math for uint256;
21+
22+
event Redeem(uint256 indexed _lockingId, address indexed _beneficiary, uint256 _amount, uint256 _batchIndex);
23+
24+
struct Batch {
25+
uint256 totalScore;
26+
// A mapping from lockingId to its score
27+
mapping(uint256=>uint) scores;
28+
mapping(uint256=>uint) redeemedScores;
29+
}
30+
31+
struct Lock {
32+
uint256 amount;
33+
uint256 lockingTime;
34+
uint256 period;
35+
}
36+
37+
// A mapping from batch index to batch
38+
mapping(uint256 => Batch) public batches;
39+
40+
uint256 public reputationRewardLeft; // the amount of reputation that is still left to distribute
41+
uint256 public startTime; // the time (in secs since epoch) that locking can start (is enable)
42+
uint256 public redeemEnableTime;
43+
uint256 public batchTime; // the length of a batch, in seconds
44+
ContinuousLocking4Reputation public cl4r;
45+
46+
uint256 constant private REAL_FBITS = 40;
47+
// What's the first non-fractional bit
48+
uint256 constant private REAL_ONE = uint256(1) << REAL_FBITS;
49+
50+
/**
51+
* @dev initialize
52+
* @param _avatar the avatar to mint reputation from
53+
* @param _cl4r the ContinuousLocking4Reputation address
54+
*/
55+
function initialize(Avatar _avatar, ContinuousLocking4Reputation _cl4r) external {
56+
super._initialize(_avatar);
57+
require(address(_cl4r) != address(0), "ContinuousLocking4Reputation reference contract must be specified");
58+
cl4r = _cl4r;
59+
startTime = _cl4r.startTime();
60+
reputationRewardLeft = _cl4r.reputationRewardLeft();
61+
redeemEnableTime = _cl4r.redeemEnableTime();
62+
batchTime = _cl4r.batchTime();
63+
}
64+
65+
/**
66+
* @dev redeem reputation function
67+
* @param _beneficiary the beneficiary to redeem.
68+
* @param _lockingId the lockingId to redeem from.
69+
* @return reputation reputation rewarded
70+
*/
71+
function redeem(address _beneficiary, uint256 _lockingId) public returns(uint256 reputation) {
72+
73+
// solhint-disable-next-line not-rely-on-time
74+
require(now > redeemEnableTime, "now > redeemEnableTime");
75+
Lock memory locker = Lock(0, 0, 0);
76+
(locker.amount, locker.lockingTime, locker.period) = cl4r.lockers(_beneficiary, _lockingId);
77+
78+
require(locker.lockingTime != 0, "_lockingId does not exist");
79+
uint256 batchIndexToRedeemFrom = (locker.lockingTime - startTime) / batchTime;
80+
// solhint-disable-next-line not-rely-on-time
81+
uint256 currentBatch = (now - startTime) / batchTime;
82+
uint256 lastBatchIndexToRedeem = currentBatch.min(batchIndexToRedeemFrom.add(locker.period));
83+
for (batchIndexToRedeemFrom; batchIndexToRedeemFrom < lastBatchIndexToRedeem; batchIndexToRedeemFrom++) {
84+
if (batches[batchIndexToRedeemFrom].scores[_lockingId] == 0) {
85+
batches[batchIndexToRedeemFrom].totalScore = cl4r.batches(batchIndexToRedeemFrom);
86+
batches[batchIndexToRedeemFrom].scores[_lockingId] = cl4r.getLockingIdScore(
87+
batchIndexToRedeemFrom, _lockingId
88+
) - batches[batchIndexToRedeemFrom].redeemedScores[_lockingId];
89+
batches[
90+
batchIndexToRedeemFrom
91+
].redeemedScores[_lockingId] += batches[batchIndexToRedeemFrom].scores[_lockingId];
92+
}
93+
Batch storage locking = batches[batchIndexToRedeemFrom];
94+
uint256 score = locking.scores[_lockingId];
95+
if (score > 0) {
96+
locking.scores[_lockingId] = 0;
97+
uint256 batchReputationReward = cl4r.getRepRewardPerBatch(batchIndexToRedeemFrom);
98+
uint256 repRelation = mul(toReal(uint216(score)), batchReputationReward);
99+
uint256 redeemForBatch = div(repRelation, toReal(uint216(locking.totalScore)));
100+
reputation = reputation.add(redeemForBatch);
101+
emit Redeem(_lockingId, _beneficiary, uint256(fromReal(redeemForBatch)), batchIndexToRedeemFrom);
102+
}
103+
}
104+
reputation = uint256(fromReal(reputation));
105+
require(reputation > 0, "reputation to redeem is 0");
106+
// check that the reputation is sum zero
107+
reputationRewardLeft = reputationRewardLeft.sub(reputation);
108+
require(
109+
Controller(avatar.owner())
110+
.mintReputation(reputation, _beneficiary), "mint reputation should succeed");
111+
}
112+
113+
/**
114+
* Multiply one real by another. Truncates overflows.
115+
*/
116+
function mul(uint256 realA, uint256 realB) private pure returns (uint256) {
117+
// When multiplying fixed point in x.y and z.w formats we get (x+z).(y+w) format.
118+
// So we just have to clip off the extra REAL_FBITS fractional bits.
119+
uint256 res = realA * realB;
120+
require(res/realA == realB, "RealMath mul overflow");
121+
return (res >> REAL_FBITS);
122+
}
123+
124+
/**
125+
* Convert an integer to a real. Preserves sign.
126+
*/
127+
function toReal(uint216 ipart) private pure returns (uint256) {
128+
return uint256(ipart) * REAL_ONE;
129+
}
130+
131+
/**
132+
* Convert a real to an integer. Preserves sign.
133+
*/
134+
function fromReal(uint256 _realValue) private pure returns (uint216) {
135+
return uint216(_realValue / REAL_ONE);
136+
}
137+
138+
/**
139+
* Divide one real by another real. Truncates overflows.
140+
*/
141+
function div(uint256 realNumerator, uint256 realDenominator) private pure returns (uint256) {
142+
// We use the reverse of the multiplication trick: convert numerator from
143+
// x.y to (x+z).(y+w) fixed point, then divide by denom in z.w fixed point.
144+
return uint256((uint256(realNumerator) * REAL_ONE) / uint256(realDenominator));
145+
}
146+
147+
}

0 commit comments

Comments
 (0)