uniswap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,335 @@
1
+ pragma :rubidity, "1.0.0"
2
+
3
+ import 'Upgradeable'
4
+ import 'UniswapV2Router'
5
+
6
+ contract :UniswapV2RouterWithRewards, is: [:UniswapV2Router, :Upgradeable], upgradeable: true do
7
+ address :public, :feeAdmin
8
+ uint256 :public, :feeBPS
9
+
10
+ uint256 :public, :swapperFeePct
11
+ uint256 :public, :stakerFeePct
12
+ uint256 :public, :protocolFeePct
13
+
14
+ mapping ({ address: :uint256 }), :public, :stakerRewardsPool
15
+ uint256 :public, :swapperRewardsPool
16
+ uint256 :public, :protocolFeePool
17
+
18
+ mapping ({ address: mapping(address: :uint256) }), :public, :stakedLP
19
+ mapping ({ address: mapping(address: :uint256) }), :public, :rewardDebt
20
+ mapping ({ address: :uint256 }), :public, :totalStakedLP
21
+ mapping ({ address: :uint256 }), :public, :accRewardsPerShare
22
+
23
+ array :address, :public, :topFiveSwappers, initial_length: 5
24
+ mapping ({ address: :uint256 }), :public, :feesGeneratedBySwapper
25
+ mapping ({ address: :uint256 }), :public, :swapperRewards
26
+
27
+ constructor(
28
+ _factory: :address,
29
+ _WETH: :address,
30
+ feeBPS: :uint256,
31
+ swapperFeePct: :uint256,
32
+ stakerFeePct: :uint256,
33
+ protocolFeePct: :uint256,
34
+ feeAdmin: :address
35
+ ) {
36
+ updateFees(
37
+ feeBPS: feeBPS,
38
+ swapperFeePct: swapperFeePct,
39
+ stakerFeePct: stakerFeePct,
40
+ protocolFeePct: protocolFeePct,
41
+ feeAdmin: feeAdmin
42
+ )
43
+
44
+ UniswapV2Router.constructor(_factory: _factory, _WETH: _WETH)
45
+ Upgradeable.constructor(upgradeAdmin: msg.sender)
46
+ }
47
+
48
+ function :updateFees, {
49
+ feeBPS: :uint256,
50
+ swapperFeePct: :uint256,
51
+ stakerFeePct: :uint256,
52
+ protocolFeePct: :uint256,
53
+ feeAdmin: :address
54
+ }, :public do
55
+ require(msg.sender == feeAdmin || s.feeAdmin == address(0), 'Only fee admin can update fees')
56
+ require(feeBPS <= 10000, 'Fee cannot be greater than 100%')
57
+ require(
58
+ swapperFeePct + stakerFeePct + protocolFeePct == 100,
59
+ 'Fees must add up to 100%'
60
+ )
61
+ require(feeAdmin != address(0), 'Fee admin cannot be address(0)')
62
+
63
+ s.feeBPS = feeBPS
64
+ s.stakerFeePct = stakerFeePct
65
+ s.swapperFeePct = swapperFeePct
66
+ s.protocolFeePct = protocolFeePct
67
+
68
+ s.feeAdmin = feeAdmin
69
+ nil
70
+ end
71
+
72
+ function :stakeLP, { lpToken: :address, amount: :uint256 }, :public, returns: :bool do
73
+ lpPair = UniswapV2Pair(lpToken)
74
+ token0 = lpPair.token0()
75
+ token1 = lpPair.token1()
76
+
77
+ require(token0 == s.WETH || token1 == s.WETH, 'One of the tokens must be WETH')
78
+ require(amount > 0, 'Amount must be greater than 0')
79
+
80
+ updateStakeAmount(lpToken: lpToken, amount: amount, isStaking: true, user: msg.sender)
81
+
82
+ ERC20(lpToken).transferFrom(msg.sender, address(this), amount)
83
+ end
84
+
85
+ function :unstakeLP, { lpToken: :address, amount: :uint256 }, :public, returns: :bool do
86
+ require(s.stakedLP[msg.sender][lpToken] >= amount, 'Insufficient staked amount')
87
+ require(amount > 0, 'Amount must be greater than 0')
88
+
89
+ updateStakeAmount(lpToken: lpToken, amount: amount, isStaking: false, user: msg.sender)
90
+
91
+ ERC20(lpToken).transfer(msg.sender, amount)
92
+ end
93
+
94
+ function :withdrawStakingRewards, { lpToken: :address }, :public do
95
+ updateStakeAmount(lpToken: lpToken, amount: 0, isStaking: true, user: msg.sender)
96
+ end
97
+
98
+ function :updateStakeAmount, {
99
+ lpToken: :address,
100
+ amount: :uint256,
101
+ isStaking: :bool,
102
+ user: :address
103
+ }, :internal do
104
+ updateStakingRewards(lpToken: lpToken)
105
+
106
+ pending = pendingStakingRewards(user: user, lpToken: lpToken)
107
+
108
+ require(pending > 0 || amount > 0, 'Nothing to do')
109
+
110
+ if pending > 0
111
+ ERC20(s.WETH).transfer(user, pending)
112
+ end
113
+
114
+ if isStaking
115
+ s.stakedLP[user][lpToken] += amount
116
+ s.totalStakedLP[lpToken] += amount
117
+ else
118
+ s.stakedLP[user][lpToken] -= amount
119
+ s.totalStakedLP[lpToken] -= amount
120
+ end
121
+
122
+ unScaledDebt = s.stakedLP[user][lpToken] * s.accRewardsPerShare[lpToken]
123
+
124
+ s.rewardDebt[user][lpToken] = unScaledDebt.div(1.ether)
125
+ nil
126
+ end
127
+
128
+ function :swapExactTokensForTokens, {
129
+ amountIn: :uint256,
130
+ amountOutMin: :uint256,
131
+ path: [:address],
132
+ to: :address,
133
+ deadline: :uint256
134
+ }, :public, :virtual, :override, returns: [:uint256] do
135
+ amounts = UniswapV2Router.swapExactTokensForTokens(
136
+ amountIn: amountIn - calculateFeeAmount(amountIn),
137
+ amountOutMin: amountOutMin,
138
+ path: path,
139
+ to: to,
140
+ deadline: deadline
141
+ )
142
+
143
+ feeInWETH = chargeFeeInWETH(amountIn, path[0])
144
+
145
+ lpToken = pairFor(factory, path[0], path[1])
146
+
147
+ s.stakerRewardsPool[lpToken] += (feeInWETH * s.stakerFeePct).div(100)
148
+ s.protocolFeePool += (feeInWETH * s.protocolFeePct).div(100)
149
+
150
+ updateTopFiveSwappers(
151
+ currentSwapper: msg.sender,
152
+ currentFee: feeInWETH
153
+ )
154
+
155
+ amounts
156
+ end
157
+
158
+ function :swapTokensForExactTokens, {
159
+ amountOut: :uint256,
160
+ amountInMax: :uint256,
161
+ path: [:address],
162
+ to: :address,
163
+ deadline: :uint256
164
+ }, :public, :virtual, :override, returns: [:uint256] do
165
+ amounts = UniswapV2Router.swapTokensForExactTokens(
166
+ amountOut: amountOut + calculateFeeAmount(amountOut),
167
+ amountInMax: amountInMax,
168
+ path: path,
169
+ to: to,
170
+ deadline: deadline
171
+ )
172
+
173
+ feeInWETH = chargeFeeInWETH(amountOut, path[1])
174
+
175
+ lpToken = pairFor(factory, path[0], path[1])
176
+
177
+ s.stakerRewardsPool[lpToken] += (feeInWETH * s.stakerFeePct).div(100)
178
+ s.protocolFeePool += (feeInWETH * s.protocolFeePct).div(100)
179
+
180
+ updateTopFiveSwappers(
181
+ currentSwapper: msg.sender,
182
+ currentFee: feeInWETH
183
+ )
184
+
185
+ amounts
186
+ end
187
+
188
+ function :calculateFeeAmount, { amount: :uint256 }, :public, :virtual, returns: :uint256 do
189
+ return (amount * s.feeBPS).div(10000)
190
+ end
191
+
192
+ function :calculateAccRewardsPerShare, { lpToken: :address }, :internal, :view, returns: :uint256 do
193
+ accRewardsPerShare = s.accRewardsPerShare[lpToken]
194
+
195
+ if s.totalStakedLP[lpToken] > 0 && s.stakerRewardsPool[lpToken] > 0
196
+ accRewardPerShareIncrement = (s.stakerRewardsPool[lpToken] * 1.ether).div(s.totalStakedLP[lpToken])
197
+ accRewardsPerShare += accRewardPerShareIncrement
198
+ end
199
+
200
+ return accRewardsPerShare
201
+ end
202
+
203
+ function :updateStakingRewards, { lpToken: :address }, :internal do
204
+ s.accRewardsPerShare[lpToken] = calculateAccRewardsPerShare(lpToken: lpToken)
205
+ s.stakerRewardsPool[lpToken] = 0
206
+ nil
207
+ end
208
+
209
+ function :pendingStakingRewards, { user: :address, lpToken: :address }, :public, :view, returns: :uint256 do
210
+ accRewardsPerShare = calculateAccRewardsPerShare(lpToken: lpToken)
211
+
212
+ topLine = (s.stakedLP[user][lpToken] * accRewardsPerShare).div(1.ether)
213
+
214
+ return topLine - s.rewardDebt[user][lpToken]
215
+ end
216
+
217
+ function :chargeFeeInWETH, {
218
+ amount: :uint256,
219
+ token: :address
220
+ }, :internal, :virtual, returns: :uint256 do
221
+ feeAmount = calculateFeeAmount(amount)
222
+
223
+ if token == s.WETH
224
+ ERC20(token).transferFrom(
225
+ from: msg.sender,
226
+ to: address(this),
227
+ amount: feeAmount
228
+ )
229
+
230
+ return feeAmount
231
+ end
232
+
233
+ path = array(:address, 2)
234
+ path[0] = token
235
+ path[1] = s.WETH
236
+
237
+ feeInWETH = UniswapV2Router.swapExactTokensForTokens(
238
+ amountIn: feeAmount,
239
+ amountOutMin: 0,
240
+ path: path,
241
+ to: address(this),
242
+ deadline: block.timestamp + 1
243
+ )[1]
244
+
245
+ return feeInWETH
246
+ end
247
+
248
+ function :updateSwapperRewards, :internal do
249
+ nonNullSwapperCount = 0
250
+
251
+ for_loop(
252
+ condition: ->(i) { i < s.topFiveSwappers.length },
253
+ max_iterations: 5
254
+ ) do |i|
255
+ if s.topFiveSwappers[i] != address(0)
256
+ nonNullSwapperCount += 1
257
+ end
258
+ end
259
+
260
+ return if nonNullSwapperCount == 0
261
+
262
+ individualSwapperReward = s.swapperRewardsPool.div(nonNullSwapperCount)
263
+
264
+ for_loop(
265
+ condition: ->(i) { i < s.topFiveSwappers.length },
266
+ max_iterations: 5
267
+ ) do |i|
268
+ swapper = s.topFiveSwappers[i]
269
+ if swapper != address(0)
270
+ s.swapperRewards[swapper] += individualSwapperReward
271
+ end
272
+ end
273
+
274
+ s.swapperRewardsPool = 0
275
+ nil
276
+ end
277
+
278
+ function :withdrawProtocolRewards, { to: :address }, :public, returns: :bool do
279
+ require(msg.sender == s.feeAdmin, "Only fee admin can withdraw protocol rewards")
280
+
281
+ amount = s.protocolFeePool
282
+ require(amount > 0, "No rewards to withdraw")
283
+
284
+ s.protocolFeePool = 0
285
+
286
+ ERC20(s.WETH).transfer(to, amount)
287
+ end
288
+
289
+ function :withdrawSwapperRewards, :public, returns: :bool do
290
+ updateSwapperRewards()
291
+
292
+ amount = s.swapperRewards[msg.sender]
293
+ require(amount > 0, "No rewards to withdraw")
294
+
295
+ s.swapperRewards[msg.sender] = 0
296
+
297
+ ERC20(s.WETH).transfer(msg.sender, amount)
298
+ end
299
+
300
+ function :updateTopFiveSwappers, { currentSwapper: :address, currentFee: :uint256 }, :internal do
301
+ updateSwapperRewards()
302
+
303
+ s.feesGeneratedBySwapper[currentSwapper] += currentFee
304
+ s.swapperRewardsPool += (currentFee * s.swapperFeePct).div(100)
305
+
306
+ newTotal = s.feesGeneratedBySwapper[currentSwapper]
307
+
308
+ for_loop(
309
+ condition: ->(i) { i < s.topFiveSwappers.length },
310
+ max_iterations: 5
311
+ ) do |i|
312
+ return if s.topFiveSwappers[i] == currentSwapper
313
+ end
314
+
315
+ minFee = 2 ** 256 - 1
316
+ minIndex = 0
317
+
318
+ for_loop(
319
+ condition: -> i { i < s.topFiveSwappers.length },
320
+ max_iterations: 5
321
+ ) do |i|
322
+ swapper = s.topFiveSwappers[i]
323
+ if swapper == address(0) || s.feesGeneratedBySwapper[swapper] < minFee
324
+ minFee = s.feesGeneratedBySwapper[swapper]
325
+ minIndex = i
326
+ end
327
+ end
328
+
329
+ if newTotal > minFee
330
+ s.topFiveSwappers[minIndex] = currentSwapper
331
+ end
332
+
333
+ nil
334
+ end
335
+ end
@@ -0,0 +1,39 @@
1
+ pragma :rubidity, "1.0.0"
2
+
3
+ import 'ERC20'
4
+
5
+ contract :UnsafeNoApprovalERC20, is: :ERC20 do
6
+ constructor(
7
+ name: :string,
8
+ symbol: :string,
9
+ ) do
10
+ super(name: name, symbol: symbol, decimals: 18)
11
+ end
12
+
13
+ function :mint, { amount: :uint256 }, :public do
14
+ require(amount > 0, 'Amount must be positive')
15
+
16
+ _mint(to: msg.sender, amount: amount)
17
+ end
18
+
19
+ function :airdrop, { to: :address, amount: :uint256 }, :public do
20
+ require(amount > 0, 'Amount must be positive')
21
+
22
+ _mint(to: to, amount: amount)
23
+ end
24
+
25
+ function :transferFrom, {
26
+ from: :address,
27
+ to: :address,
28
+ amount: :uint256
29
+ }, :public, :override, returns: :bool do
30
+ require(s.balanceOf[from] >= amount, 'Insufficient balance')
31
+
32
+ s.balanceOf[from] -= amount
33
+ s.balanceOf[to] += amount
34
+
35
+ emit :Transfer, from: from, to: to, amount: amount
36
+
37
+ return true
38
+ end
39
+ end
data/lib/uniswap.rb ADDED
@@ -0,0 +1,11 @@
1
+
2
+ require 'solidity/typed'
3
+ require 'rubidity'
4
+
5
+
6
+ ## our own code
7
+ require_relative 'uniswap/ERC20'
8
+ require_relative 'uniswap/UniswapV2ERC20'
9
+ require_relative 'uniswap/UniswapV2Pair'
10
+
11
+ puts "bye"
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: uniswap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubidity
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rdoc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '7'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '4.0'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: hoe
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '4.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '4.0'
61
+ description: uniswap - core uniswap v2 (dumb) contracts for ruby (rubidity) for layer
62
+ 1 (l1) with "off-chain" indexer
63
+ email: gerald.bauer@gmail.com
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files:
67
+ - CHANGELOG.md
68
+ - Manifest.txt
69
+ - README.md
70
+ files:
71
+ - CHANGELOG.md
72
+ - Manifest.txt
73
+ - README.md
74
+ - Rakefile
75
+ - lib/uniswap.rb
76
+ - lib/uniswap/ERC20.rb
77
+ - lib/uniswap/PublicMintERC20.rb
78
+ - lib/uniswap/UniswapSetupZapV2.rb
79
+ - lib/uniswap/UniswapV2Callee.rb
80
+ - lib/uniswap/UniswapV2ERC20.rb
81
+ - lib/uniswap/UniswapV2Factory.rb
82
+ - lib/uniswap/UniswapV2Pair.rb
83
+ - lib/uniswap/UniswapV2Router.rb
84
+ - lib/uniswap/UniswapV2RouterWithRewards.rb
85
+ - lib/uniswap/UnsafeNoApprovalERC20.rb
86
+ homepage: https://github.com/s6ruby/rubidity
87
+ licenses:
88
+ - Public Domain
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options:
92
+ - "--main"
93
+ - README.md
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '2.3'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.4.10
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: uniswap - core uniswap v2 (dumb) contracts for ruby (rubidity) for layer
111
+ 1 (l1) with "off-chain" indexer
112
+ test_files: []