Skip to content

Commit 26e9b3a

Browse files
committed
add veFeeEstimate
1 parent 0c13ae2 commit 26e9b3a

File tree

4 files changed

+412
-7
lines changed

4 files changed

+412
-7
lines changed

addresses/address.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"veFeeDistributor": "0xB99BAA8D5b131c9140Be2F13EA6D2494DF272919",
2424
"veDelegationProxy": "0x7b886fa12a9b11BD0cb83e79398070CD635BcBdF",
2525
"DFRewards": "0xD09BCDC099D635A0D8A7f003DC01F645382B6700",
26-
"DFStrategyV1": "0x2Fe41338f11d7402E31A4b902F60077164C65a52"
26+
"DFStrategyV1": "0x2Fe41338f11d7402E31A4b902F60077164C65a52",
27+
"veFeeEstimate": "0x65B5E9e8Bb08D2c20a93311E724D2eCC06C1ffb5"
2728
},
2829
"mumbai": {
2930
"chainId": 80001,
@@ -49,7 +50,8 @@
4950
"veFeeDistributor": "0x35F1e6765750E874EB9d0675393A1A394A4749b4",
5051
"veDelegationProxy": "0x51B1b14b8bfb43a2fB0b49843787Ca440200F6b7",
5152
"DFRewards": "0x4259c164eedA7483dda2b4b622D761A88674D31f",
52-
"DFStrategyV1": "0x1be9C72500B41c286C797D4FE727747Ae9C4E195"
53+
"DFStrategyV1": "0x1be9C72500B41c286C797D4FE727747Ae9C4E195",
54+
"veFeeEstimate": "0xCFeF55c6ae4d250586e293f29832967a04A9087d"
5355
},
5456
"ropsten": {
5557
"chainId": 3,
@@ -75,7 +77,8 @@
7577
"veFeeDistributor": "0x1be9C72500B41c286C797D4FE727747Ae9C4E195",
7678
"veDelegationProxy": "0xDD6b48CcDFdaa84F868aA18418236e52c2eA26A6",
7779
"DFRewards": "0x409AA28a9815fcBFc7e5489c3DA45c84b2f36721",
78-
"DFStrategyV1": "0xCFeF55c6ae4d250586e293f29832967a04A9087d"
80+
"DFStrategyV1": "0xCFeF55c6ae4d250586e293f29832967a04A9087d",
81+
"veFeeEstimate": "0x4CD3027E8B8e59D3a38c028Cb6EC25240bF52cDB"
7982
},
8083
"moonbase": {
8184
"chainId": 1287,
@@ -224,7 +227,8 @@
224227
"veFeeDistributor": "0xd09789Ce05aa0f6feFc18315de4964Db07Cc0618",
225228
"veDelegationProxy": "0x257fe2e49530A4B7FC3Ed597465e2931db3f20b7",
226229
"DFRewards": "0x6fd867E5AEE6D62a24f97939db90C4e67A73A651",
227-
"DFStrategyV1": "0x1Af3CC30fD18af837f7630Aff12aE2b826bD3c5D"
230+
"DFStrategyV1": "0x1Af3CC30fD18af837f7630Aff12aE2b826bD3c5D",
231+
"veFeeEstimate": "0x85Aa84868993e2C07Ef3Ba965ea4693dbf82fD28"
228232
},
229233
"polygonedge": {
230234
"chainId": 81001,

contracts/ve/veFeeEstimate.vy

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# @version 0.2.7
2+
"""
3+
@title Curve Fee Estimate
4+
@author Ocean Protocol
5+
@license MIT
6+
"""
7+
8+
from vyper.interfaces import ERC20
9+
10+
11+
interface VotingEscrow:
12+
def user_point_epoch(addr: address) -> uint256: view
13+
def epoch() -> uint256: view
14+
def user_point_history(addr: address, loc: uint256) -> Point: view
15+
def point_history(loc: uint256) -> Point: view
16+
def checkpoint(): nonpayable
17+
18+
interface FeeDistributor:
19+
def last_token_time() -> uint256: view
20+
def start_time() -> uint256: view
21+
def time_cursor() -> uint256: view
22+
def time_cursor_of(addr: address) -> uint256: view
23+
def user_epoch_of(addr: address) -> uint256: view
24+
def tokens_per_week(week: uint256) -> uint256: view
25+
def ve_supply(week: uint256) -> uint256: view
26+
27+
struct Point:
28+
bias: int128
29+
slope: int128 # - dweight / dt
30+
ts: uint256
31+
blk: uint256 # block
32+
33+
34+
WEEK: constant(uint256) = 7 * 86400
35+
TOKEN_CHECKPOINT_DEADLINE: constant(uint256) = 86400
36+
37+
voting_escrow: public(address)
38+
fee_distributor: public(address)
39+
40+
41+
42+
@external
43+
def __init__(
44+
_voting_escrow: address,
45+
_fee_distributor: address,
46+
):
47+
"""
48+
@notice Contract constructor
49+
@param _voting_escrow VotingEscrow contract address
50+
@param _fee_distributor FeeDistributor contract address
51+
"""
52+
self.voting_escrow = _voting_escrow
53+
self.fee_distributor = _fee_distributor
54+
55+
@internal
56+
def _find_timestamp_epoch(ve: address, _timestamp: uint256) -> uint256:
57+
_min: uint256 = 0
58+
_max: uint256 = VotingEscrow(ve).epoch()
59+
for i in range(128):
60+
if _min >= _max:
61+
break
62+
_mid: uint256 = (_min + _max + 2) / 2
63+
pt: Point = VotingEscrow(ve).point_history(_mid)
64+
if pt.ts <= _timestamp:
65+
_min = _mid
66+
else:
67+
_max = _mid - 1
68+
return _min
69+
70+
@view
71+
@internal
72+
def _find_timestamp_user_epoch(ve: address, user: address, _timestamp: uint256, max_user_epoch: uint256) -> uint256:
73+
_min: uint256 = 0
74+
_max: uint256 = max_user_epoch
75+
for i in range(128):
76+
if _min >= _max:
77+
break
78+
_mid: uint256 = (_min + _max + 2) / 2
79+
pt: Point = VotingEscrow(ve).user_point_history(user, _mid)
80+
if pt.ts <= _timestamp:
81+
_min = _mid
82+
else:
83+
_max = _mid - 1
84+
return _min
85+
86+
87+
88+
@external
89+
@view
90+
def estimateClaim(addr: address) -> uint256:
91+
# Minimal user_epoch is 0 (if user had no point)
92+
user_epoch: uint256 = 0
93+
to_distribute: uint256 = 0
94+
95+
max_user_epoch: uint256 = VotingEscrow(self.voting_escrow).user_point_epoch(addr)
96+
_start_time: uint256 = FeeDistributor(self.fee_distributor).start_time()
97+
_last_token_time: uint256 = FeeDistributor(self.fee_distributor).last_token_time()
98+
99+
if max_user_epoch == 0:
100+
# No lock = no fees
101+
return 0
102+
103+
week_cursor: uint256 = FeeDistributor(self.fee_distributor).time_cursor_of(addr)
104+
if week_cursor == 0:
105+
# Need to do the initial binary search
106+
user_epoch = self._find_timestamp_user_epoch(self.voting_escrow, addr, _start_time, max_user_epoch)
107+
else:
108+
user_epoch = FeeDistributor(self.fee_distributor).user_epoch_of(addr)
109+
110+
if user_epoch == 0:
111+
user_epoch = 1
112+
113+
user_point: Point = VotingEscrow(self.voting_escrow).user_point_history(addr, user_epoch)
114+
115+
if week_cursor == 0:
116+
week_cursor = (user_point.ts + WEEK - 1) / WEEK * WEEK
117+
118+
if week_cursor >= _last_token_time:
119+
return 0
120+
121+
if week_cursor < _start_time:
122+
week_cursor = _start_time
123+
old_user_point: Point = empty(Point)
124+
125+
# Iterate over weeks
126+
for i in range(50):
127+
if week_cursor >= _last_token_time:
128+
break
129+
130+
if week_cursor >= user_point.ts and user_epoch <= max_user_epoch:
131+
user_epoch += 1
132+
old_user_point = user_point
133+
if user_epoch > max_user_epoch:
134+
user_point = empty(Point)
135+
else:
136+
user_point = VotingEscrow(self.voting_escrow).user_point_history(addr, user_epoch)
137+
138+
else:
139+
# Calc
140+
# + i * 2 is for rounding errors
141+
dt: int128 = convert(week_cursor - old_user_point.ts, int128)
142+
balance_of: uint256 = convert(max(old_user_point.bias - dt * old_user_point.slope, 0), uint256)
143+
if balance_of == 0 and user_epoch > max_user_epoch:
144+
break
145+
if balance_of > 0:
146+
tokens_per_week: uint256 = FeeDistributor(self.fee_distributor).tokens_per_week(week_cursor)
147+
ve_supply: uint256 = FeeDistributor(self.fee_distributor).ve_supply(week_cursor)
148+
if ve_supply !=0 and tokens_per_week !=0:
149+
to_distribute += balance_of * tokens_per_week/ ve_supply
150+
151+
week_cursor += WEEK
152+
153+
154+
return to_distribute

scripts/deploy-contracts.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,30 @@ async function main() {
8282
gasLimit = 6000000;
8383
gasPrice = ethers.utils.parseUnits('25', 'gwei')
8484
sleepAmount = 1
85+
shouldDeployV4 = false;
86+
shouldDeployDF = true;
87+
shouldDeployVE = true;
8588
break;
8689
case 0x4:
8790
networkName = "rinkeby";
8891
OceanTokenAddress = "0x8967bcf84170c91b0d24d4302c2376283b0b3a07";
8992
OPFOwner = "0x0e901bC5D49636eC75B3B4fB88238698E5322dE6";
9093
routerOwner = OPFOwner;
9194
sleepAmount = 2
95+
shouldDeployV4 = false;
96+
shouldDeployDF = true;
97+
shouldDeployVE = true;
9298
break;
9399
case 0x5:
94100
networkName = "goerli";
95101
OceanTokenAddress = "0xCfDdA22C9837aE76E0faA845354f33C62E03653a";
96102
OPFOwner = "0xEE1673089A4831D92324932e38e2EBDe6aB17274";
97103
routerOwner = OPFOwner;
98-
shouldDeployOceanToken = false;
99-
shouldDeployDF = false;
100-
shouldDeployVE = false;
101104
sleepAmount = 2
102105
gasPrice = ethers.utils.parseUnits('5', 'gwei')
106+
shouldDeployV4 = false;
107+
shouldDeployDF = true;
108+
shouldDeployVE = true;
103109
break;
104110
case 0x89:
105111
networkName = "polygon";
@@ -148,6 +154,10 @@ async function main() {
148154
gasLimit = 15000000
149155
gasPrice = ethers.utils.parseUnits('45', 'gwei')
150156
sleepAmount = 2
157+
shouldDeployOceanToken = false;
158+
shouldDeployV4 = false;
159+
shouldDeployDF = true;
160+
shouldDeployVE = true;
151161
break;
152162
case 0x38:
153163
networkName = "bsc";
@@ -550,6 +560,21 @@ async function main() {
550560
console.log("\tnpx hardhat verify --network " + networkName + " " + addresses.veDelegationProxy + " " + addresses.veDelegation + " " + routerOwner + " " + owner.address)
551561
}
552562
if (sleepAmount > 0) await sleep(sleepAmount)
563+
564+
//veFeeEstimate
565+
if (logging) console.info("Deploying veFeeEstimate");
566+
const veFeeEstimate = await ethers.getContractFactory("veFeeEstimate", owner);
567+
const deployedVeFeeEstimate = await veFeeEstimate.connect(owner).deploy(
568+
addresses.veOCEAN,
569+
addresses.veFeeDistributor,
570+
options);
571+
await deployedVeFeeEstimate.deployTransaction.wait();
572+
addresses.veFeeEstimate = deployedVeFeeEstimate.address;
573+
if(show_verify){
574+
console.log("\tRun the following to verify on etherscan");
575+
console.log("\tnpx hardhat verify --network "+networkName+" "+addresses.veFeeEstimate+" "+addresses.veOCEAN+" "+addresses.veFeeDistributor)
576+
}
577+
553578
}
554579

555580
//DF contracts

0 commit comments

Comments
 (0)