uniswap 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []