├── .gitignore
├── README.md
├── assets
└── abi
│ ├── aave_abi.json
│ ├── classic_pool_factory_address.json
│ ├── classic_pool_syncswap_data.json
│ ├── deploy.json
│ ├── dmail.json
│ ├── erc20.json
│ ├── eth.json
│ ├── eth_claim.json
│ ├── l2pass_abi.json
│ ├── layerbank.json
│ ├── main_bridge.json
│ ├── main_bridge_scroll.json
│ ├── omnisea_abi.json
│ ├── oracle.json
│ ├── punkswap.json
│ ├── rubyscore_abi.json
│ ├── scroll_citizen_abi.json
│ ├── skydrome.json
│ ├── spacefi.json
│ ├── syncswap.json
│ ├── zebra_abi.json
│ ├── zerius.json
│ └── zkstars_abi.json
├── config.py
├── main.py
├── okx_data
├── okx_data.py
└── okx_wallets.txt
├── requirements.txt
├── src
├── database
│ ├── data
│ │ └── analytics_data.py
│ ├── models.py
│ └── utils.py
├── modules
│ ├── bridges
│ │ ├── main_bridge
│ │ │ ├── main_bridge.py
│ │ │ └── utils
│ │ │ │ ├── data
│ │ │ │ └── proof_data
│ │ │ │ │ ├── request_data.py
│ │ │ │ │ └── txsbyhashes.py
│ │ │ │ └── transaction_data.py
│ │ ├── orbiter
│ │ │ ├── oribter_bridge.py
│ │ │ └── utils
│ │ │ │ └── transaction_data.py
│ │ └── owlto
│ │ │ ├── owlto_bridge.py
│ │ │ └── utils
│ │ │ └── transaction_data.py
│ ├── deploy
│ │ ├── contract
│ │ │ └── contract.sol
│ │ ├── contract_deployer.py
│ │ └── utils
│ │ │ └── data_exctract.py
│ ├── dmail
│ │ └── dmail.py
│ ├── lendings
│ │ ├── aave
│ │ │ └── aave.py
│ │ └── layerbank
│ │ │ └── layerbank.py
│ ├── nft
│ │ ├── l2pass
│ │ │ └── l2pass.py
│ │ ├── omnisea
│ │ │ └── omnisea.py
│ │ ├── scrollcitizen
│ │ │ └── scrollcitizen.py
│ │ ├── zerius
│ │ │ ├── utils
│ │ │ │ └── data.py
│ │ │ └── zerius.py
│ │ └── zkstars
│ │ │ └── zkstars.py
│ ├── okx_withdraw
│ │ ├── okx_withdraw.py
│ │ └── utils
│ │ │ ├── data.py
│ │ │ └── okx_sub_transfer.py
│ ├── other
│ │ ├── multi_approve
│ │ │ └── multi_approve.py
│ │ └── rubyscore
│ │ │ └── rubyscore.py
│ └── swaps
│ │ ├── punk_swap
│ │ ├── punk_swap.py
│ │ └── utils
│ │ │ └── transaction_data.py
│ │ ├── skydrome
│ │ ├── skydrome_swap.py
│ │ └── utils
│ │ │ └── transaction_data.py
│ │ ├── spacefi
│ │ ├── spacefi_swap.py
│ │ └── utils
│ │ │ └── transaction_data.py
│ │ ├── sync_swap
│ │ ├── sync_swap.py
│ │ └── utils
│ │ │ └── transaction_data.py
│ │ ├── wrapper
│ │ ├── eth_wrapper.py
│ │ └── transaction_data.py
│ │ └── zebra
│ │ ├── utils
│ │ └── transaction_data.py
│ │ └── zebra.py
└── utils
│ ├── base_bridge.py
│ ├── base_liquidity.py
│ ├── base_liquidity_remove.py
│ ├── base_mint.py
│ ├── base_swap.py
│ ├── data
│ ├── chains.py
│ ├── contracts.py
│ ├── helper.py
│ ├── mappings.py
│ ├── tokens.py
│ └── types.py
│ ├── errors
│ └── exceptions.py
│ ├── gas_checker.py
│ ├── logger.py
│ ├── runner.py
│ ├── user
│ ├── account.py
│ └── utils.py
│ └── wrappers
│ └── decorators.py
└── wallets.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,pycharm,venv
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,pycharm,venv
3 |
4 | ### macOS ###
5 | # General
6 | .DS_Store
7 | .AppleDouble
8 | .LSOverride
9 |
10 | # Icon must end with two \r
11 | Icon
12 |
13 |
14 | # Thumbnails
15 | ._*
16 |
17 | # Files that might appear in the root of a volume
18 | .DocumentRevisions-V100
19 | .fseventsd
20 | .Spotlight-V100
21 | .TemporaryItems
22 | .Trashes
23 | .VolumeIcon.icns
24 | .com.apple.timemachine.donotpresent
25 |
26 | # Directories potentially created on remote AFP share
27 | .AppleDB
28 | .AppleDesktop
29 | Network Trash Folder
30 | Temporary Items
31 | .apdisk
32 |
33 | ### macOS Patch ###
34 | # iCloud generated files
35 | *.icloud
36 |
37 | ### PyCharm ###
38 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
39 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
40 |
41 | # User-specific stuff
42 | .idea/**/workspace.xml
43 | .idea/**/tasks.xml
44 | .idea/**/usage.statistics.xml
45 | .idea/**/dictionaries
46 | .idea/**/shelf
47 |
48 | # AWS User-specific
49 | .idea/**/aws.xml
50 |
51 | # Generated files
52 | .idea/**/contentModel.xml
53 |
54 | # Sensitive or high-churn files
55 | .idea/**/dataSources/
56 | .idea/**/dataSources.ids
57 | .idea/**/dataSources.local.xml
58 | .idea/**/sqlDataSources.xml
59 | .idea/**/dynamic.xml
60 | .idea/**/uiDesigner.xml
61 | .idea/**/dbnavigator.xml
62 |
63 | # Gradle
64 | .idea/**/gradle.xml
65 | .idea/**/libraries
66 |
67 | # Gradle and Maven with auto-import
68 | # When using Gradle or Maven with auto-import, you should exclude module files,
69 | # since they will be recreated, and may cause churn. Uncomment if using
70 | # auto-import.
71 | # .idea/artifacts
72 | # .idea/compiler.xml
73 | # .idea/jarRepositories.xml
74 | # .idea/modules.xml
75 | # .idea/*.iml
76 | # .idea/modules
77 | # *.iml
78 | # *.ipr
79 |
80 | # CMake
81 | cmake-build-*/
82 |
83 | # Mongo Explorer plugin
84 | .idea/**/mongoSettings.xml
85 |
86 | # File-based project format
87 | *.iws
88 |
89 | # IntelliJ
90 | out/
91 |
92 | # mpeltonen/sbt-idea plugin
93 | .idea_modules/
94 |
95 | # JIRA plugin
96 | atlassian-ide-plugin.xml
97 |
98 | # Cursive Clojure plugin
99 | .idea/replstate.xml
100 |
101 | # SonarLint plugin
102 | .idea/sonarlint/
103 |
104 | # Crashlytics plugin (for Android Studio and IntelliJ)
105 | com_crashlytics_export_strings.xml
106 | crashlytics.properties
107 | crashlytics-build.properties
108 | fabric.properties
109 |
110 | # Editor-based Rest Client
111 | .idea/httpRequests
112 |
113 | # Android studio 3.1+ serialized cache file
114 | .idea/caches/build_file_checksums.ser
115 |
116 | ### PyCharm Patch ###
117 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
118 |
119 | # *.iml
120 | # modules.xml
121 | # .idea/misc.xml
122 | # *.ipr
123 |
124 | # Sonarlint plugin
125 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
126 | .idea/**/sonarlint/
127 |
128 | # SonarQube Plugin
129 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
130 | .idea/**/sonarIssues.xml
131 |
132 | # Markdown Navigator plugin
133 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
134 | .idea/**/markdown-navigator.xml
135 | .idea/**/markdown-navigator-enh.xml
136 | .idea/**/markdown-navigator/
137 |
138 | # Cache file creation bug
139 | # See https://youtrack.jetbrains.com/issue/JBR-2257
140 | .idea/$CACHE_FILE$
141 |
142 | # CodeStream plugin
143 | # https://plugins.jetbrains.com/plugin/12206-codestream
144 | .idea/codestream.xml
145 |
146 | # Azure Toolkit for IntelliJ plugin
147 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
148 | .idea/**/azureSettings.xml
149 |
150 | ### venv ###
151 | # Virtualenv
152 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
153 | .Python
154 | [Bb]in
155 | [Ii]nclude
156 | [Ll]ib
157 | [Ll]ib64
158 | [Ll]ocal
159 | [Ss]cripts
160 | pyvenv.cfg
161 | .venv
162 | pip-selfcheck.json
163 |
164 | # End of https://www.toptal.com/developers/gitignore/api/macos,pycharm,venv
165 | poetry.lock
166 | pyproject.toml
167 | __pycache__/
168 | */__pycache__/
169 | .idea/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Scroll Soft
2 |
3 | Script to interact with contracts in Scroll.
4 |
5 | TG: https://t.me/cryptoscripts
6 |
7 | Donations: 0x763cDEa4a54991Cd85bFAd1FD47E9c175f53090B
8 |
9 | ---
10 |
11 | Modules
12 |
13 | 1. Main Bridge (deposit/withdraw)
14 |
15 | 2. Orbiter bridge
16 |
17 | 3. Swaps on PunkSwap, SkyDrome, SpaceFi
18 |
19 | 4. Liquidity on PunkSwap, SkyDrome, SpaceFi
20 |
21 | 5. Dmail
22 |
23 | 6. Zerius (Mint + Bridge)
24 |
25 | 7. Deposit from OKX / Withdraw to OKX
26 |
27 | 8. All transactions are saved to the database.
28 |
29 | ---
30 | Some information
31 |
32 | The routes are made randomly so that the patterns on the wallets do not match.
33 | There is a random pause between module executions, which can also be configured.
34 | You can also adjust the maximum gas value, thereby reducing transaction fees.
35 | The script implements a circular system with output to OKX sub-accounts,
36 | you can simply launch the bot with a balance on OKX, and it will scroll
37 | through all your wallets. In order for the cycle system to work, you need to enable
38 | at least one bridge each with deposit and withdrawal variables.
39 | In the future, we will be able to immediately withdraw money to OKX
40 | as soon as they add such an option. Also, all transactions will be stored in a
41 | database. The database will also contain information about how many interactions
42 | there were with a certain contract and the volumes on it.
43 |
44 | ---
45 | Settings
46 |
47 | To configure modules you need to go to the file config.py.
48 | Inside there will be information on each variable in a specific module type. For other modules, for example,
49 | for another swap on some dex, the settings work in the same way
50 |
--------------------------------------------------------------------------------
/assets/abi/aave_abi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "address",
6 | "name": "weth",
7 | "type": "address"
8 | },
9 | {
10 | "internalType": "address",
11 | "name": "owner",
12 | "type": "address"
13 | },
14 | {
15 | "internalType": "contract IPool",
16 | "name": "pool",
17 | "type": "address"
18 | }
19 | ],
20 | "stateMutability": "nonpayable",
21 | "type": "constructor"
22 | },
23 | {
24 | "anonymous": false,
25 | "inputs": [
26 | {
27 | "indexed": true,
28 | "internalType": "address",
29 | "name": "previousOwner",
30 | "type": "address"
31 | },
32 | {
33 | "indexed": true,
34 | "internalType": "address",
35 | "name": "newOwner",
36 | "type": "address"
37 | }
38 | ],
39 | "name": "OwnershipTransferred",
40 | "type": "event"
41 | },
42 | {
43 | "stateMutability": "payable",
44 | "type": "fallback"
45 | },
46 | {
47 | "inputs": [
48 | {
49 | "internalType": "address",
50 | "name": "",
51 | "type": "address"
52 | },
53 | {
54 | "internalType": "uint256",
55 | "name": "amount",
56 | "type": "uint256"
57 | },
58 | {
59 | "internalType": "uint256",
60 | "name": "interestRateMode",
61 | "type": "uint256"
62 | },
63 | {
64 | "internalType": "uint16",
65 | "name": "referralCode",
66 | "type": "uint16"
67 | }
68 | ],
69 | "name": "borrowETH",
70 | "outputs": [],
71 | "stateMutability": "nonpayable",
72 | "type": "function"
73 | },
74 | {
75 | "inputs": [
76 | {
77 | "internalType": "address",
78 | "name": "",
79 | "type": "address"
80 | },
81 | {
82 | "internalType": "address",
83 | "name": "onBehalfOf",
84 | "type": "address"
85 | },
86 | {
87 | "internalType": "uint16",
88 | "name": "referralCode",
89 | "type": "uint16"
90 | }
91 | ],
92 | "name": "depositETH",
93 | "outputs": [],
94 | "stateMutability": "payable",
95 | "type": "function"
96 | },
97 | {
98 | "inputs": [
99 | {
100 | "internalType": "address",
101 | "name": "to",
102 | "type": "address"
103 | },
104 | {
105 | "internalType": "uint256",
106 | "name": "amount",
107 | "type": "uint256"
108 | }
109 | ],
110 | "name": "emergencyEtherTransfer",
111 | "outputs": [],
112 | "stateMutability": "nonpayable",
113 | "type": "function"
114 | },
115 | {
116 | "inputs": [
117 | {
118 | "internalType": "address",
119 | "name": "token",
120 | "type": "address"
121 | },
122 | {
123 | "internalType": "address",
124 | "name": "to",
125 | "type": "address"
126 | },
127 | {
128 | "internalType": "uint256",
129 | "name": "amount",
130 | "type": "uint256"
131 | }
132 | ],
133 | "name": "emergencyTokenTransfer",
134 | "outputs": [],
135 | "stateMutability": "nonpayable",
136 | "type": "function"
137 | },
138 | {
139 | "inputs": [],
140 | "name": "getWETHAddress",
141 | "outputs": [
142 | {
143 | "internalType": "address",
144 | "name": "",
145 | "type": "address"
146 | }
147 | ],
148 | "stateMutability": "view",
149 | "type": "function"
150 | },
151 | {
152 | "inputs": [],
153 | "name": "owner",
154 | "outputs": [
155 | {
156 | "internalType": "address",
157 | "name": "",
158 | "type": "address"
159 | }
160 | ],
161 | "stateMutability": "view",
162 | "type": "function"
163 | },
164 | {
165 | "inputs": [],
166 | "name": "renounceOwnership",
167 | "outputs": [],
168 | "stateMutability": "nonpayable",
169 | "type": "function"
170 | },
171 | {
172 | "inputs": [
173 | {
174 | "internalType": "address",
175 | "name": "",
176 | "type": "address"
177 | },
178 | {
179 | "internalType": "uint256",
180 | "name": "amount",
181 | "type": "uint256"
182 | },
183 | {
184 | "internalType": "uint256",
185 | "name": "rateMode",
186 | "type": "uint256"
187 | },
188 | {
189 | "internalType": "address",
190 | "name": "onBehalfOf",
191 | "type": "address"
192 | }
193 | ],
194 | "name": "repayETH",
195 | "outputs": [],
196 | "stateMutability": "payable",
197 | "type": "function"
198 | },
199 | {
200 | "inputs": [
201 | {
202 | "internalType": "address",
203 | "name": "newOwner",
204 | "type": "address"
205 | }
206 | ],
207 | "name": "transferOwnership",
208 | "outputs": [],
209 | "stateMutability": "nonpayable",
210 | "type": "function"
211 | },
212 | {
213 | "inputs": [
214 | {
215 | "internalType": "address",
216 | "name": "",
217 | "type": "address"
218 | },
219 | {
220 | "internalType": "uint256",
221 | "name": "amount",
222 | "type": "uint256"
223 | },
224 | {
225 | "internalType": "address",
226 | "name": "to",
227 | "type": "address"
228 | }
229 | ],
230 | "name": "withdrawETH",
231 | "outputs": [],
232 | "stateMutability": "nonpayable",
233 | "type": "function"
234 | },
235 | {
236 | "inputs": [
237 | {
238 | "internalType": "address",
239 | "name": "",
240 | "type": "address"
241 | },
242 | {
243 | "internalType": "uint256",
244 | "name": "amount",
245 | "type": "uint256"
246 | },
247 | {
248 | "internalType": "address",
249 | "name": "to",
250 | "type": "address"
251 | },
252 | {
253 | "internalType": "uint256",
254 | "name": "deadline",
255 | "type": "uint256"
256 | },
257 | {
258 | "internalType": "uint8",
259 | "name": "permitV",
260 | "type": "uint8"
261 | },
262 | {
263 | "internalType": "bytes32",
264 | "name": "permitR",
265 | "type": "bytes32"
266 | },
267 | {
268 | "internalType": "bytes32",
269 | "name": "permitS",
270 | "type": "bytes32"
271 | }
272 | ],
273 | "name": "withdrawETHWithPermit",
274 | "outputs": [],
275 | "stateMutability": "nonpayable",
276 | "type": "function"
277 | },
278 | {
279 | "stateMutability": "payable",
280 | "type": "receive"
281 | }
282 | ]
--------------------------------------------------------------------------------
/assets/abi/classic_pool_factory_address.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "address",
6 | "name": "_master",
7 | "type": "address"
8 | }
9 | ],
10 | "stateMutability": "nonpayable",
11 | "type": "constructor"
12 | },
13 | {
14 | "inputs": [],
15 | "name": "InvalidTokens",
16 | "type": "error"
17 | },
18 | {
19 | "anonymous": false,
20 | "inputs": [
21 | {
22 | "indexed": true,
23 | "internalType": "address",
24 | "name": "token0",
25 | "type": "address"
26 | },
27 | {
28 | "indexed": true,
29 | "internalType": "address",
30 | "name": "token1",
31 | "type": "address"
32 | },
33 | {
34 | "indexed": false,
35 | "internalType": "address",
36 | "name": "pool",
37 | "type": "address"
38 | }
39 | ],
40 | "name": "PoolCreated",
41 | "type": "event"
42 | },
43 | {
44 | "inputs": [
45 | {
46 | "internalType": "bytes",
47 | "name": "data",
48 | "type": "bytes"
49 | }
50 | ],
51 | "name": "createPool",
52 | "outputs": [
53 | {
54 | "internalType": "address",
55 | "name": "pool",
56 | "type": "address"
57 | }
58 | ],
59 | "stateMutability": "nonpayable",
60 | "type": "function"
61 | },
62 | {
63 | "inputs": [],
64 | "name": "getDeployData",
65 | "outputs": [
66 | {
67 | "internalType": "bytes",
68 | "name": "deployData",
69 | "type": "bytes"
70 | }
71 | ],
72 | "stateMutability": "view",
73 | "type": "function"
74 | },
75 | {
76 | "inputs": [
77 | {
78 | "internalType": "address",
79 | "name": "",
80 | "type": "address"
81 | },
82 | {
83 | "internalType": "address",
84 | "name": "",
85 | "type": "address"
86 | }
87 | ],
88 | "name": "getPool",
89 | "outputs": [
90 | {
91 | "internalType": "address",
92 | "name": "",
93 | "type": "address"
94 | }
95 | ],
96 | "stateMutability": "view",
97 | "type": "function"
98 | },
99 | {
100 | "inputs": [
101 | {
102 | "internalType": "address",
103 | "name": "pool",
104 | "type": "address"
105 | },
106 | {
107 | "internalType": "address",
108 | "name": "sender",
109 | "type": "address"
110 | },
111 | {
112 | "internalType": "address",
113 | "name": "tokenIn",
114 | "type": "address"
115 | },
116 | {
117 | "internalType": "address",
118 | "name": "tokenOut",
119 | "type": "address"
120 | },
121 | {
122 | "internalType": "bytes",
123 | "name": "data",
124 | "type": "bytes"
125 | }
126 | ],
127 | "name": "getSwapFee",
128 | "outputs": [
129 | {
130 | "internalType": "uint24",
131 | "name": "swapFee",
132 | "type": "uint24"
133 | }
134 | ],
135 | "stateMutability": "view",
136 | "type": "function"
137 | },
138 | {
139 | "inputs": [],
140 | "name": "master",
141 | "outputs": [
142 | {
143 | "internalType": "address",
144 | "name": "",
145 | "type": "address"
146 | }
147 | ],
148 | "stateMutability": "view",
149 | "type": "function"
150 | }
151 | ]
--------------------------------------------------------------------------------
/assets/abi/deploy.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [],
4 | "stateMutability": "nonpayable",
5 | "type": "constructor"
6 | },
7 | {
8 | "inputs": [],
9 | "name": "message",
10 | "outputs": [
11 | {
12 | "internalType": "string",
13 | "name": "",
14 | "type": "string"
15 | }
16 | ],
17 | "stateMutability": "view",
18 | "type": "function"
19 | },
20 | {
21 | "inputs": [
22 | {
23 | "internalType": "string",
24 | "name": "newMessage",
25 | "type": "string"
26 | }
27 | ],
28 | "name": "setMessage",
29 | "outputs": [],
30 | "stateMutability": "nonpayable",
31 | "type": "function"
32 | }
33 | ]
--------------------------------------------------------------------------------
/assets/abi/erc20.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "string",
6 | "name": "_name",
7 | "type": "string"
8 | },
9 | {
10 | "internalType": "string",
11 | "name": "_symbol",
12 | "type": "string"
13 | },
14 | {
15 | "internalType": "uint256",
16 | "name": "_initialSupply",
17 | "type": "uint256"
18 | }
19 | ],
20 | "stateMutability": "nonpayable",
21 | "type": "constructor"
22 | },
23 | {
24 | "anonymous": false,
25 | "inputs": [
26 | {
27 | "indexed": true,
28 | "internalType": "address",
29 | "name": "owner",
30 | "type": "address"
31 | },
32 | {
33 | "indexed": true,
34 | "internalType": "address",
35 | "name": "spender",
36 | "type": "address"
37 | },
38 | {
39 | "indexed": false,
40 | "internalType": "uint256",
41 | "name": "value",
42 | "type": "uint256"
43 | }
44 | ],
45 | "name": "Approval",
46 | "type": "event"
47 | },
48 | {
49 | "anonymous": false,
50 | "inputs": [
51 | {
52 | "indexed": true,
53 | "internalType": "address",
54 | "name": "from",
55 | "type": "address"
56 | },
57 | {
58 | "indexed": true,
59 | "internalType": "address",
60 | "name": "to",
61 | "type": "address"
62 | },
63 | {
64 | "indexed": false,
65 | "internalType": "uint256",
66 | "name": "value",
67 | "type": "uint256"
68 | }
69 | ],
70 | "name": "Transfer",
71 | "type": "event"
72 | },
73 | {
74 | "inputs": [
75 | {
76 | "internalType": "address",
77 | "name": "owner",
78 | "type": "address"
79 | },
80 | {
81 | "internalType": "address",
82 | "name": "spender",
83 | "type": "address"
84 | }
85 | ],
86 | "name": "allowance",
87 | "outputs": [
88 | {
89 | "internalType": "uint256",
90 | "name": "",
91 | "type": "uint256"
92 | }
93 | ],
94 | "stateMutability": "view",
95 | "type": "function"
96 | },
97 | {
98 | "inputs": [
99 | {
100 | "internalType": "address",
101 | "name": "spender",
102 | "type": "address"
103 | },
104 | {
105 | "internalType": "uint256",
106 | "name": "amount",
107 | "type": "uint256"
108 | }
109 | ],
110 | "name": "approve",
111 | "outputs": [
112 | {
113 | "internalType": "bool",
114 | "name": "",
115 | "type": "bool"
116 | }
117 | ],
118 | "stateMutability": "nonpayable",
119 | "type": "function"
120 | },
121 | {
122 | "inputs": [
123 | {
124 | "internalType": "address",
125 | "name": "account",
126 | "type": "address"
127 | }
128 | ],
129 | "name": "balanceOf",
130 | "outputs": [
131 | {
132 | "internalType": "uint256",
133 | "name": "",
134 | "type": "uint256"
135 | }
136 | ],
137 | "stateMutability": "view",
138 | "type": "function"
139 | },
140 | {
141 | "inputs": [],
142 | "name": "decimals",
143 | "outputs": [
144 | {
145 | "internalType": "uint8",
146 | "name": "",
147 | "type": "uint8"
148 | }
149 | ],
150 | "stateMutability": "view",
151 | "type": "function"
152 | },
153 | {
154 | "inputs": [
155 | {
156 | "internalType": "address",
157 | "name": "spender",
158 | "type": "address"
159 | },
160 | {
161 | "internalType": "uint256",
162 | "name": "subtractedValue",
163 | "type": "uint256"
164 | }
165 | ],
166 | "name": "decreaseAllowance",
167 | "outputs": [
168 | {
169 | "internalType": "bool",
170 | "name": "",
171 | "type": "bool"
172 | }
173 | ],
174 | "stateMutability": "nonpayable",
175 | "type": "function"
176 | },
177 | {
178 | "inputs": [
179 | {
180 | "internalType": "address",
181 | "name": "spender",
182 | "type": "address"
183 | },
184 | {
185 | "internalType": "uint256",
186 | "name": "addedValue",
187 | "type": "uint256"
188 | }
189 | ],
190 | "name": "increaseAllowance",
191 | "outputs": [
192 | {
193 | "internalType": "bool",
194 | "name": "",
195 | "type": "bool"
196 | }
197 | ],
198 | "stateMutability": "nonpayable",
199 | "type": "function"
200 | },
201 | {
202 | "inputs": [],
203 | "name": "name",
204 | "outputs": [
205 | {
206 | "internalType": "string",
207 | "name": "",
208 | "type": "string"
209 | }
210 | ],
211 | "stateMutability": "view",
212 | "type": "function"
213 | },
214 | {
215 | "inputs": [
216 | {
217 | "internalType": "uint8",
218 | "name": "decimals_",
219 | "type": "uint8"
220 | }
221 | ],
222 | "name": "setupDecimals",
223 | "outputs": [],
224 | "stateMutability": "nonpayable",
225 | "type": "function"
226 | },
227 | {
228 | "inputs": [],
229 | "name": "symbol",
230 | "outputs": [
231 | {
232 | "internalType": "string",
233 | "name": "",
234 | "type": "string"
235 | }
236 | ],
237 | "stateMutability": "view",
238 | "type": "function"
239 | },
240 | {
241 | "inputs": [],
242 | "name": "totalSupply",
243 | "outputs": [
244 | {
245 | "internalType": "uint256",
246 | "name": "",
247 | "type": "uint256"
248 | }
249 | ],
250 | "stateMutability": "view",
251 | "type": "function"
252 | },
253 | {
254 | "inputs": [
255 | {
256 | "internalType": "address",
257 | "name": "recipient",
258 | "type": "address"
259 | },
260 | {
261 | "internalType": "uint256",
262 | "name": "amount",
263 | "type": "uint256"
264 | }
265 | ],
266 | "name": "transfer",
267 | "outputs": [
268 | {
269 | "internalType": "bool",
270 | "name": "",
271 | "type": "bool"
272 | }
273 | ],
274 | "stateMutability": "nonpayable",
275 | "type": "function"
276 | },
277 | {
278 | "inputs": [
279 | {
280 | "internalType": "address",
281 | "name": "sender",
282 | "type": "address"
283 | },
284 | {
285 | "internalType": "address",
286 | "name": "recipient",
287 | "type": "address"
288 | },
289 | {
290 | "internalType": "uint256",
291 | "name": "amount",
292 | "type": "uint256"
293 | }
294 | ],
295 | "name": "transferFrom",
296 | "outputs": [
297 | {
298 | "internalType": "bool",
299 | "name": "",
300 | "type": "bool"
301 | }
302 | ],
303 | "stateMutability": "nonpayable",
304 | "type": "function"
305 | }
306 | ]
--------------------------------------------------------------------------------
/assets/abi/eth.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": false,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "internalType": "address",
8 | "name": "src",
9 | "type": "address"
10 | },
11 | {
12 | "indexed": true,
13 | "internalType": "address",
14 | "name": "guy",
15 | "type": "address"
16 | },
17 | {
18 | "indexed": false,
19 | "internalType": "uint256",
20 | "name": "wad",
21 | "type": "uint256"
22 | }
23 | ],
24 | "name": "Approval",
25 | "type": "event"
26 | },
27 | {
28 | "anonymous": false,
29 | "inputs": [
30 | {
31 | "indexed": true,
32 | "internalType": "address",
33 | "name": "dst",
34 | "type": "address"
35 | },
36 | {
37 | "indexed": false,
38 | "internalType": "uint256",
39 | "name": "wad",
40 | "type": "uint256"
41 | }
42 | ],
43 | "name": "Deposit",
44 | "type": "event"
45 | },
46 | {
47 | "anonymous": false,
48 | "inputs": [
49 | {
50 | "indexed": true,
51 | "internalType": "address",
52 | "name": "src",
53 | "type": "address"
54 | },
55 | {
56 | "indexed": true,
57 | "internalType": "address",
58 | "name": "dst",
59 | "type": "address"
60 | },
61 | {
62 | "indexed": false,
63 | "internalType": "uint256",
64 | "name": "wad",
65 | "type": "uint256"
66 | }
67 | ],
68 | "name": "Transfer",
69 | "type": "event"
70 | },
71 | {
72 | "anonymous": false,
73 | "inputs": [
74 | {
75 | "indexed": true,
76 | "internalType": "address",
77 | "name": "src",
78 | "type": "address"
79 | },
80 | {
81 | "indexed": false,
82 | "internalType": "uint256",
83 | "name": "wad",
84 | "type": "uint256"
85 | }
86 | ],
87 | "name": "Withdrawal",
88 | "type": "event"
89 | },
90 | {
91 | "payable": true,
92 | "stateMutability": "payable",
93 | "type": "fallback"
94 | },
95 | {
96 | "constant": true,
97 | "inputs": [
98 | {
99 | "internalType": "address",
100 | "name": "",
101 | "type": "address"
102 | },
103 | {
104 | "internalType": "address",
105 | "name": "",
106 | "type": "address"
107 | }
108 | ],
109 | "name": "allowance",
110 | "outputs": [
111 | {
112 | "internalType": "uint256",
113 | "name": "",
114 | "type": "uint256"
115 | }
116 | ],
117 | "payable": false,
118 | "stateMutability": "view",
119 | "type": "function"
120 | },
121 | {
122 | "constant": false,
123 | "inputs": [
124 | {
125 | "internalType": "address",
126 | "name": "guy",
127 | "type": "address"
128 | },
129 | {
130 | "internalType": "uint256",
131 | "name": "wad",
132 | "type": "uint256"
133 | }
134 | ],
135 | "name": "approve",
136 | "outputs": [
137 | {
138 | "internalType": "bool",
139 | "name": "",
140 | "type": "bool"
141 | }
142 | ],
143 | "payable": false,
144 | "stateMutability": "nonpayable",
145 | "type": "function"
146 | },
147 | {
148 | "constant": true,
149 | "inputs": [
150 | {
151 | "internalType": "address",
152 | "name": "",
153 | "type": "address"
154 | }
155 | ],
156 | "name": "balanceOf",
157 | "outputs": [
158 | {
159 | "internalType": "uint256",
160 | "name": "",
161 | "type": "uint256"
162 | }
163 | ],
164 | "payable": false,
165 | "stateMutability": "view",
166 | "type": "function"
167 | },
168 | {
169 | "constant": true,
170 | "inputs": [],
171 | "name": "decimals",
172 | "outputs": [
173 | {
174 | "internalType": "uint8",
175 | "name": "",
176 | "type": "uint8"
177 | }
178 | ],
179 | "payable": false,
180 | "stateMutability": "view",
181 | "type": "function"
182 | },
183 | {
184 | "constant": false,
185 | "inputs": [],
186 | "name": "deposit",
187 | "outputs": [],
188 | "payable": true,
189 | "stateMutability": "payable",
190 | "type": "function"
191 | },
192 | {
193 | "constant": true,
194 | "inputs": [],
195 | "name": "name",
196 | "outputs": [
197 | {
198 | "internalType": "string",
199 | "name": "",
200 | "type": "string"
201 | }
202 | ],
203 | "payable": false,
204 | "stateMutability": "view",
205 | "type": "function"
206 | },
207 | {
208 | "constant": true,
209 | "inputs": [],
210 | "name": "symbol",
211 | "outputs": [
212 | {
213 | "internalType": "string",
214 | "name": "",
215 | "type": "string"
216 | }
217 | ],
218 | "payable": false,
219 | "stateMutability": "view",
220 | "type": "function"
221 | },
222 | {
223 | "constant": true,
224 | "inputs": [],
225 | "name": "totalSupply",
226 | "outputs": [
227 | {
228 | "internalType": "uint256",
229 | "name": "",
230 | "type": "uint256"
231 | }
232 | ],
233 | "payable": false,
234 | "stateMutability": "view",
235 | "type": "function"
236 | },
237 | {
238 | "constant": false,
239 | "inputs": [
240 | {
241 | "internalType": "address",
242 | "name": "dst",
243 | "type": "address"
244 | },
245 | {
246 | "internalType": "uint256",
247 | "name": "wad",
248 | "type": "uint256"
249 | }
250 | ],
251 | "name": "transfer",
252 | "outputs": [
253 | {
254 | "internalType": "bool",
255 | "name": "",
256 | "type": "bool"
257 | }
258 | ],
259 | "payable": false,
260 | "stateMutability": "nonpayable",
261 | "type": "function"
262 | },
263 | {
264 | "constant": false,
265 | "inputs": [
266 | {
267 | "internalType": "address",
268 | "name": "src",
269 | "type": "address"
270 | },
271 | {
272 | "internalType": "address",
273 | "name": "dst",
274 | "type": "address"
275 | },
276 | {
277 | "internalType": "uint256",
278 | "name": "wad",
279 | "type": "uint256"
280 | }
281 | ],
282 | "name": "transferFrom",
283 | "outputs": [
284 | {
285 | "internalType": "bool",
286 | "name": "",
287 | "type": "bool"
288 | }
289 | ],
290 | "payable": false,
291 | "stateMutability": "nonpayable",
292 | "type": "function"
293 | },
294 | {
295 | "constant": false,
296 | "inputs": [
297 | {
298 | "internalType": "uint256",
299 | "name": "wad",
300 | "type": "uint256"
301 | }
302 | ],
303 | "name": "withdraw",
304 | "outputs": [],
305 | "payable": false,
306 | "stateMutability": "nonpayable",
307 | "type": "function"
308 | }
309 | ]
--------------------------------------------------------------------------------
/assets/abi/omnisea_abi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "address",
6 | "name": "_scheduler",
7 | "type": "address"
8 | },
9 | {
10 | "internalType": "address",
11 | "name": "_universalONFT",
12 | "type": "address"
13 | },
14 | {
15 | "internalType": "address",
16 | "name": "_omniseaERC721Psi",
17 | "type": "address"
18 | }
19 | ],
20 | "stateMutability": "nonpayable",
21 | "type": "constructor"
22 | },
23 | {
24 | "anonymous": false,
25 | "inputs": [
26 | {
27 | "indexed": true,
28 | "internalType": "address",
29 | "name": "collection",
30 | "type": "address"
31 | }
32 | ],
33 | "name": "Created",
34 | "type": "event"
35 | },
36 | {
37 | "inputs": [
38 | {
39 | "components": [
40 | {
41 | "internalType": "string",
42 | "name": "name",
43 | "type": "string"
44 | },
45 | {
46 | "internalType": "string",
47 | "name": "symbol",
48 | "type": "string"
49 | },
50 | {
51 | "internalType": "string",
52 | "name": "uri",
53 | "type": "string"
54 | },
55 | {
56 | "internalType": "string",
57 | "name": "tokensURI",
58 | "type": "string"
59 | },
60 | {
61 | "internalType": "uint24",
62 | "name": "maxSupply",
63 | "type": "uint24"
64 | },
65 | {
66 | "internalType": "bool",
67 | "name": "isZeroIndexed",
68 | "type": "bool"
69 | },
70 | {
71 | "internalType": "uint24",
72 | "name": "royaltyAmount",
73 | "type": "uint24"
74 | },
75 | {
76 | "internalType": "uint256",
77 | "name": "endTime",
78 | "type": "uint256"
79 | }
80 | ],
81 | "internalType": "struct CreateParams",
82 | "name": "_params",
83 | "type": "tuple"
84 | }
85 | ],
86 | "name": "create",
87 | "outputs": [],
88 | "stateMutability": "nonpayable",
89 | "type": "function"
90 | },
91 | {
92 | "inputs": [
93 | {
94 | "internalType": "address",
95 | "name": "",
96 | "type": "address"
97 | }
98 | ],
99 | "name": "drops",
100 | "outputs": [
101 | {
102 | "internalType": "bool",
103 | "name": "",
104 | "type": "bool"
105 | }
106 | ],
107 | "stateMutability": "view",
108 | "type": "function"
109 | },
110 | {
111 | "inputs": [],
112 | "name": "omniseaERC721Psi",
113 | "outputs": [
114 | {
115 | "internalType": "address",
116 | "name": "",
117 | "type": "address"
118 | }
119 | ],
120 | "stateMutability": "view",
121 | "type": "function"
122 | },
123 | {
124 | "inputs": [],
125 | "name": "owner",
126 | "outputs": [
127 | {
128 | "internalType": "address",
129 | "name": "",
130 | "type": "address"
131 | }
132 | ],
133 | "stateMutability": "view",
134 | "type": "function"
135 | },
136 | {
137 | "inputs": [],
138 | "name": "scheduler",
139 | "outputs": [
140 | {
141 | "internalType": "address",
142 | "name": "",
143 | "type": "address"
144 | }
145 | ],
146 | "stateMutability": "view",
147 | "type": "function"
148 | },
149 | {
150 | "inputs": [
151 | {
152 | "internalType": "address",
153 | "name": "manager_",
154 | "type": "address"
155 | }
156 | ],
157 | "name": "setManager",
158 | "outputs": [],
159 | "stateMutability": "nonpayable",
160 | "type": "function"
161 | },
162 | {
163 | "inputs": [],
164 | "name": "universalONFT",
165 | "outputs": [
166 | {
167 | "internalType": "address",
168 | "name": "",
169 | "type": "address"
170 | }
171 | ],
172 | "stateMutability": "view",
173 | "type": "function"
174 | }
175 | ]
--------------------------------------------------------------------------------
/assets/abi/oracle.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [],
4 | "stateMutability": "nonpayable",
5 | "type": "constructor"
6 | },
7 | {
8 | "anonymous": false,
9 | "inputs": [
10 | {
11 | "indexed": false,
12 | "internalType": "uint8",
13 | "name": "version",
14 | "type": "uint8"
15 | }
16 | ],
17 | "name": "Initialized",
18 | "type": "event"
19 | },
20 | {
21 | "anonymous": false,
22 | "inputs": [
23 | {
24 | "indexed": false,
25 | "internalType": "uint256",
26 | "name": "txGas",
27 | "type": "uint256"
28 | },
29 | {
30 | "indexed": false,
31 | "internalType": "uint256",
32 | "name": "txGasContractCreation",
33 | "type": "uint256"
34 | },
35 | {
36 | "indexed": false,
37 | "internalType": "uint256",
38 | "name": "zeroGas",
39 | "type": "uint256"
40 | },
41 | {
42 | "indexed": false,
43 | "internalType": "uint256",
44 | "name": "nonZeroGas",
45 | "type": "uint256"
46 | }
47 | ],
48 | "name": "IntrinsicParamsUpdated",
49 | "type": "event"
50 | },
51 | {
52 | "anonymous": false,
53 | "inputs": [
54 | {
55 | "indexed": false,
56 | "internalType": "uint256",
57 | "name": "oldL2BaseFee",
58 | "type": "uint256"
59 | },
60 | {
61 | "indexed": false,
62 | "internalType": "uint256",
63 | "name": "newL2BaseFee",
64 | "type": "uint256"
65 | }
66 | ],
67 | "name": "L2BaseFeeUpdated",
68 | "type": "event"
69 | },
70 | {
71 | "anonymous": false,
72 | "inputs": [
73 | {
74 | "indexed": true,
75 | "internalType": "address",
76 | "name": "previousOwner",
77 | "type": "address"
78 | },
79 | {
80 | "indexed": true,
81 | "internalType": "address",
82 | "name": "newOwner",
83 | "type": "address"
84 | }
85 | ],
86 | "name": "OwnershipTransferred",
87 | "type": "event"
88 | },
89 | {
90 | "anonymous": false,
91 | "inputs": [
92 | {
93 | "indexed": false,
94 | "internalType": "address",
95 | "name": "_oldWhitelist",
96 | "type": "address"
97 | },
98 | {
99 | "indexed": false,
100 | "internalType": "address",
101 | "name": "_newWhitelist",
102 | "type": "address"
103 | }
104 | ],
105 | "name": "UpdateWhitelist",
106 | "type": "event"
107 | },
108 | {
109 | "inputs": [
110 | {
111 | "internalType": "bytes",
112 | "name": "_message",
113 | "type": "bytes"
114 | }
115 | ],
116 | "name": "calculateIntrinsicGasFee",
117 | "outputs": [
118 | {
119 | "internalType": "uint256",
120 | "name": "",
121 | "type": "uint256"
122 | }
123 | ],
124 | "stateMutability": "view",
125 | "type": "function"
126 | },
127 | {
128 | "inputs": [
129 | {
130 | "internalType": "uint256",
131 | "name": "_gasLimit",
132 | "type": "uint256"
133 | }
134 | ],
135 | "name": "estimateCrossDomainMessageFee",
136 | "outputs": [
137 | {
138 | "internalType": "uint256",
139 | "name": "",
140 | "type": "uint256"
141 | }
142 | ],
143 | "stateMutability": "view",
144 | "type": "function"
145 | },
146 | {
147 | "inputs": [
148 | {
149 | "internalType": "uint64",
150 | "name": "_txGas",
151 | "type": "uint64"
152 | },
153 | {
154 | "internalType": "uint64",
155 | "name": "_txGasContractCreation",
156 | "type": "uint64"
157 | },
158 | {
159 | "internalType": "uint64",
160 | "name": "_zeroGas",
161 | "type": "uint64"
162 | },
163 | {
164 | "internalType": "uint64",
165 | "name": "_nonZeroGas",
166 | "type": "uint64"
167 | }
168 | ],
169 | "name": "initialize",
170 | "outputs": [],
171 | "stateMutability": "nonpayable",
172 | "type": "function"
173 | },
174 | {
175 | "inputs": [],
176 | "name": "intrinsicParams",
177 | "outputs": [
178 | {
179 | "internalType": "uint64",
180 | "name": "txGas",
181 | "type": "uint64"
182 | },
183 | {
184 | "internalType": "uint64",
185 | "name": "txGasContractCreation",
186 | "type": "uint64"
187 | },
188 | {
189 | "internalType": "uint64",
190 | "name": "zeroGas",
191 | "type": "uint64"
192 | },
193 | {
194 | "internalType": "uint64",
195 | "name": "nonZeroGas",
196 | "type": "uint64"
197 | }
198 | ],
199 | "stateMutability": "view",
200 | "type": "function"
201 | },
202 | {
203 | "inputs": [],
204 | "name": "l2BaseFee",
205 | "outputs": [
206 | {
207 | "internalType": "uint256",
208 | "name": "",
209 | "type": "uint256"
210 | }
211 | ],
212 | "stateMutability": "view",
213 | "type": "function"
214 | },
215 | {
216 | "inputs": [],
217 | "name": "owner",
218 | "outputs": [
219 | {
220 | "internalType": "address",
221 | "name": "",
222 | "type": "address"
223 | }
224 | ],
225 | "stateMutability": "view",
226 | "type": "function"
227 | },
228 | {
229 | "inputs": [],
230 | "name": "renounceOwnership",
231 | "outputs": [],
232 | "stateMutability": "nonpayable",
233 | "type": "function"
234 | },
235 | {
236 | "inputs": [
237 | {
238 | "internalType": "uint64",
239 | "name": "_txGas",
240 | "type": "uint64"
241 | },
242 | {
243 | "internalType": "uint64",
244 | "name": "_txGasContractCreation",
245 | "type": "uint64"
246 | },
247 | {
248 | "internalType": "uint64",
249 | "name": "_zeroGas",
250 | "type": "uint64"
251 | },
252 | {
253 | "internalType": "uint64",
254 | "name": "_nonZeroGas",
255 | "type": "uint64"
256 | }
257 | ],
258 | "name": "setIntrinsicParams",
259 | "outputs": [],
260 | "stateMutability": "nonpayable",
261 | "type": "function"
262 | },
263 | {
264 | "inputs": [
265 | {
266 | "internalType": "uint256",
267 | "name": "_newL2BaseFee",
268 | "type": "uint256"
269 | }
270 | ],
271 | "name": "setL2BaseFee",
272 | "outputs": [],
273 | "stateMutability": "nonpayable",
274 | "type": "function"
275 | },
276 | {
277 | "inputs": [
278 | {
279 | "internalType": "address",
280 | "name": "newOwner",
281 | "type": "address"
282 | }
283 | ],
284 | "name": "transferOwnership",
285 | "outputs": [],
286 | "stateMutability": "nonpayable",
287 | "type": "function"
288 | },
289 | {
290 | "inputs": [
291 | {
292 | "internalType": "address",
293 | "name": "_newWhitelist",
294 | "type": "address"
295 | }
296 | ],
297 | "name": "updateWhitelist",
298 | "outputs": [],
299 | "stateMutability": "nonpayable",
300 | "type": "function"
301 | },
302 | {
303 | "inputs": [],
304 | "name": "whitelist",
305 | "outputs": [
306 | {
307 | "internalType": "contract IWhitelist",
308 | "name": "",
309 | "type": "address"
310 | }
311 | ],
312 | "stateMutability": "view",
313 | "type": "function"
314 | }
315 | ]
--------------------------------------------------------------------------------
/assets/abi/rubyscore_abi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "stateMutability": "payable",
4 | "type": "fallback"
5 | },
6 | {
7 | "inputs": [],
8 | "name": "vote",
9 | "outputs": [],
10 | "stateMutability": "payable",
11 | "type": "function"
12 | }
13 | ]
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | RANDOMIZE = True
2 | SLIPPAGE = 0.03
3 | MIN_PAUSE = 10
4 | MAX_PAUSE = 20
5 | RETRIES = 3
6 | PAUSE_BETWEEN_RETRIES = 1
7 | CHECK_GWEI = False
8 | MAX_GWEI = 25
9 | USE_DATABASE = False
10 |
11 | deploy_contract = False
12 |
13 |
14 | # --- Other --- #
15 | dmail = False
16 | rubyscore = False
17 | multi_approve = True
18 |
19 | # --- Lendings --- #
20 | layerbank_deposit = False
21 | layerbank_withdraw = False
22 | aave_deposit = False
23 | aave_withdraw = False
24 |
25 |
26 | # --- Bridges --- #
27 | main_bridge = False
28 | owl_bridge = False
29 | orbiter_bridge = False
30 |
31 | # --- Swaps --- #
32 | skydrome_swap = False
33 | punk_swap = False
34 | zebra_swap = False
35 | syncswap_swap = False
36 | specefi_swap = False
37 | wrapper = False
38 |
39 | swap_all_to_eth = False
40 | random_dex_swap = False
41 |
42 | # --- Liquidity --- #
43 | punk_swap_liquidity = False
44 | punk_swap_liquidity_remove = False
45 |
46 | spacefi_liquidity = False
47 | spacefi_liquidity_remove = False
48 |
49 | syncswap_liquidity = True
50 | syncswap_liquidity_remove = False
51 |
52 | skydrome_liquidity = False
53 | skydrome_liquidity_remove = False
54 |
55 | random_add_liquidity = False
56 |
57 | # --- NFT --- #
58 | zerius = False
59 | l2pass = False
60 | omnisea = False
61 | scroll_citizen = False
62 | zk_stars = False
63 |
64 | # --- Withdrawals --- #
65 | okx_withdraw = False # from okx to wallets
66 | okx_deposit = False # from wallets to okx
67 |
68 |
69 | class OkxWithdrawConfig:
70 | """
71 | OKX => Wallets
72 |
73 | amount: Union[float, List[float]].
74 | chain: str. ERC20 - Ethereum.
75 | """
76 |
77 | amount = [0.001, 0.002]
78 | chain = 'ERC-20'
79 |
80 |
81 | class WithdrawFromWalletsToOKXConfig:
82 | """
83 | Wallets => OKX
84 |
85 | amount: Union[float, List[float]].
86 | from_chain: str. ETH, ERA, etc.
87 | withdraw_all: bool. True/False.
88 | keep_value: Union[float, List[float]]. ETH value to keep on your wallet if withdraw_all = True.
89 | """
90 | amount = [0.001, 0.002]
91 | from_chain = 'ARB'
92 | withdraw_all = True
93 | keep_value = [0.005, 0.007]
94 |
95 |
96 | class MainBridgeConfig:
97 | """
98 | action: str. deposit/withdraw.
99 | amount: Union[float, List[float]]. Value to bridge. You can use float or list. e.g. amount = 0.5 (will bridge 0.5 ETH)
100 | or amount = [0.5, 0.6] (will randomly take a number between 0.5 and 0.6)
101 |
102 | use_percentage: bool. Use True if you want to use a percentage of the balance instead of numbers.
103 |
104 | bridge_percentage: Union[float, List[float]]. Value as a percentage of balance to bridge.
105 | You can use float or list. e.g. bridge_percentage = 0.5 (will bridge 50% of your ETH balance)
106 | or bridge_percentage = [0.5, 0.6] (will randomly take a number between 50% and 60%)
107 |
108 | """
109 | action = 'withdraw'
110 | amount = [0.1, 0.2]
111 | use_percentage = True
112 | bridge_percentage = [0.5, 0.5]
113 | claim_eth = False # True is only if you withdraw from Scroll to ETH (need to wait for ~40 minutes after bridge)
114 |
115 |
116 | class OrbiterBridgeConfig:
117 | """
118 | chains: eth, arb, op, era, base, scroll
119 |
120 | action: deposit/withdraw
121 | """
122 | action = 'deposit'
123 |
124 | from_chain = 'ARB'
125 | to_chain = 'SCROLL'
126 | amount = [0.05, 0.06]
127 | use_percentage = False
128 | bridge_percentage = [0.5, 0.5]
129 |
130 |
131 | class OwlBridgeConfig:
132 | """
133 | """
134 | action = 'deposit'
135 |
136 | from_chain = 'SCROLL'
137 | to_chain = 'ARB'
138 | amount = 0.004
139 | use_percentage = False
140 | bridge_percentage = [0.5, 0.5]
141 |
142 |
143 | class SwapAllTokensConfig:
144 | tokens_list = ['WETH', 'USDC', 'USDT', 'WBTC', 'DAI']
145 | to_token = 'ETH'
146 |
147 |
148 | class RandomDexSwapConfig:
149 | from_token = 'ETH'
150 | to_token = ['USDC', 'USDT', 'WBTC', 'DAI']
151 | amount = [0.001, 0.003]
152 | use_percentage = False
153 | swap_percentage = [0.1, 0.2]
154 | num_swaps = [1, 4]
155 |
156 |
157 | class SyncSwapSwapConfig:
158 | """
159 | from_token: str.
160 | to_token: str | list[str]. If to_token = ['USDC', 'USDT'] it will randomly take USDT or USDC.
161 | """
162 |
163 | from_token = 'ETH'
164 | to_token = ['USDC', 'USDT']
165 | amount = 0.001
166 | use_percentage = False
167 | swap_percentage = 0.5
168 | swap_all_balance = True
169 |
170 |
171 | # --- Swaps --- #
172 | class SkyDromeSwapConfig:
173 | from_token = 'WETH'
174 | to_token = 'USDC'
175 | amount = 0.0024
176 | use_percentage = False
177 | swap_percentage = 0.5
178 | swap_all_balance = True
179 |
180 |
181 | class ZebraSwapConfig:
182 | from_token = 'USDT'
183 | to_token = 'ETH'
184 | amount = 0.0024
185 | use_percentage = False
186 | swap_percentage = [0.1, 0.2]
187 | swap_all_balance = True
188 |
189 |
190 | class SpaceFiSwapConfig:
191 | from_token = 'ETH'
192 | to_token = 'USDT'
193 | amount = 0.002
194 | use_percentage = False
195 | swap_percentage = 0.5
196 | swap_all_balance = True
197 |
198 |
199 | class PunkSwapConfig:
200 | from_token = 'USDC'
201 | to_token = 'ETH'
202 | amount = [0.0009, 0.0011]
203 | use_percentage = False
204 | swap_percentage = 0.1
205 | swap_all_balance = True
206 |
207 |
208 | class WrapperConfig:
209 | """
210 | action: str. Wrap/Unwrap.
211 | amount: Union[float, List[float]].
212 | use_all_balance: bool. True is only for action = Unwrap.
213 | use_percentage: bool. True/False.
214 | percentage_to_wrap: Union[List[float], float].
215 | """
216 |
217 | action = 'unwrap'
218 | amount = [0.001, 0.002]
219 | use_all_balance = False
220 | use_percentage = True
221 | percentage_to_wrap = [0.1, 0.2]
222 |
223 |
224 | class RandomLiquidityConfig:
225 | token = 'ETH'
226 | token2 = ['USDT']
227 | amount = [0.0004, 0.0004]
228 | use_percentage = True
229 | liquidity_percentage = [0.1, 0.2]
230 | num_transactions = [1, 1]
231 |
232 |
233 | class PunkSwapLiquidityConfig:
234 | token = 'USDC'
235 | token2 = 'USDT'
236 | amount = [1, 1]
237 | use_percentage = False
238 | liquidity_percentage = 0.01
239 |
240 |
241 | class SpaceFiLiquidityConfig:
242 | token = 'USDC'
243 | token2 = 'USDT'
244 | amount = [1, 1]
245 | use_percentage = False
246 | liquidity_percentage = 0.01
247 |
248 |
249 | class SyncSwapLiquidityConfig:
250 | token = 'ETH'
251 | token2 = 'USDC'
252 | amount = [0.001, 0.001]
253 | use_percentage = False
254 | liquidity_percentage = 0.01
255 |
256 |
257 | class SyncSwapLiquidityRemoveConfig:
258 | token = 'ETH'
259 | token2 = 'USDC'
260 | removing_percentage = 0.5
261 | remove_all = True
262 |
263 |
264 | class PunkSwapLiquidityRemoveConfig:
265 | token = 'USDC'
266 | token2 = 'USDT'
267 | removing_percentage = 0.5
268 | remove_all = True
269 |
270 |
271 | class SpaceFiLiquidityRemoveConfig:
272 | token = 'USDC'
273 | token2 = 'USDT'
274 | removing_percentage = 0.5
275 | remove_all = True
276 |
277 |
278 | class SkyDromeLiquidityConfig:
279 | token = 'ETH'
280 | token2 = 'USDC'
281 | amount = [0.001, 0.001]
282 | use_percentage = False
283 | liquidity_percentage = 0.01
284 |
285 |
286 | class SkyDromeLiquidityRemoveConfig:
287 | token = 'USDC'
288 | token2 = 'USDT'
289 | removing_percentage = 0.5
290 | remove_all = True
291 |
292 |
293 | class DmailConfig:
294 | num_transactions = 1
295 |
296 |
297 | class ZeruisConfig:
298 | """
299 | chain_to_bridge: Union[str, List[str]]: ['ARB', 'OP', 'POLYGON', 'BSC', 'AVAX']
300 | """
301 | chain_to_bridge = ['ARB', 'OP', 'POLYGON', 'BSC', 'AVAX']
302 |
303 |
304 | class DeployerConfig:
305 | use_0x_bytecode = True
306 |
307 |
308 | class LayerBankDepositConfig:
309 | """
310 | action: str. deposit/withdraw
311 | amount: Union[float, List[float]]
312 | use_percentage: bool. True/False
313 | percentage: float. 0 - 1.
314 | """
315 |
316 | amount = [0.0005, 0.001]
317 | use_percentage = True
318 | percentage = [0.85, 0.9]
319 | only_collateral = False
320 |
321 |
322 | class LayerBankWithdrawConfig:
323 | amount = [0.001, 0.002]
324 | withdraw_all = True
325 | use_percentage = False
326 | percentage = 0.01
327 |
328 |
329 | class AaveDepositConfig:
330 | amount = [0.001, 0.002]
331 | use_percentage = True
332 | percentage = [0.1, 0.2]
333 |
334 |
335 | class AaveWithdrawConfig:
336 | amount = [0.001, 0.002]
337 | withdraw_all = True
338 | use_percentage = False
339 | percentage = [0.1, 0.2]
340 |
341 |
342 | class ScrollCitizenMintConfig:
343 | mint_all = False
344 | quantity = [1, 2]
345 |
346 |
347 | class ZkStarsMintConfig:
348 | mint_all = False
349 | quantity = [1, 2]
350 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | from typing import Awaitable
4 |
5 | from asyncio import (
6 | create_task,
7 | gather,
8 | sleep,
9 | run
10 | )
11 |
12 | from loguru import logger
13 | from config import *
14 |
15 | from src.utils.data.mappings import module_handlers
16 | from src.utils.wrappers.decorators import check_gas
17 |
18 | from src.utils.data.helper import (
19 | private_keys,
20 | active_module,
21 | )
22 |
23 |
24 | @check_gas
25 | async def process_task(private_key: str, pattern: str) -> None:
26 | await module_handlers[pattern](private_key)
27 |
28 |
29 | async def main() -> None:
30 | bridge_mappings = {
31 | 'main_bridge': MainBridgeConfig,
32 | 'orbiter_bridge': OrbiterBridgeConfig,
33 | 'owl_bridge': OwlBridgeConfig
34 | }
35 | tasks = []
36 |
37 | random.shuffle(private_keys)
38 | for private_key in private_keys:
39 | patterns = active_module.copy()
40 |
41 | if RANDOMIZE:
42 | random.shuffle(patterns)
43 | lendings = [['layerbank_deposit', 'layerbank_withdraw'], ['aave_deposit', 'aave_withdraw']]
44 |
45 | bridge_patterns = ['main_bridge', 'orbiter_bridge', 'owl_bridge']
46 | deposit_bridges = []
47 | withdraw_bridges = []
48 | for bridge_pattern in bridge_patterns:
49 | if bridge_pattern in patterns and bridge_mappings[bridge_pattern].action.lower() == 'deposit':
50 | deposit_bridges.append(bridge_pattern)
51 | elif bridge_pattern in patterns and bridge_mappings[bridge_pattern].action.lower() == 'withdraw':
52 | withdraw_bridges.append(bridge_pattern)
53 |
54 | if deposit_bridges:
55 | random_deposit_bridge = random.choice(deposit_bridges)
56 | patterns.remove(random_deposit_bridge)
57 | patterns.insert(0, random_deposit_bridge)
58 | deposit_bridges.remove(random_deposit_bridge)
59 |
60 | for deposit_bridge in deposit_bridges:
61 | patterns.remove(deposit_bridge)
62 |
63 | if 'okx_withdraw' in patterns:
64 | patterns.remove('okx_withdraw')
65 | patterns.insert(0, 'okx_withdraw')
66 | if 'swap_all_to_eth' in patterns:
67 | patterns.remove('swap_all_to_eth')
68 | patterns.append('swap_all_to_eth')
69 | for lending in lendings:
70 | if lending[0] in patterns:
71 | patterns.remove(lending[0])
72 | patterns.append(lending[0])
73 | if lending[1] in patterns:
74 | patterns.remove(lending[1])
75 | patterns.append(lending[1])
76 |
77 | if withdraw_bridges:
78 | random_withdraw_bridge = random.choice(withdraw_bridges)
79 | patterns.remove(random_withdraw_bridge)
80 | patterns.append(random_withdraw_bridge)
81 | withdraw_bridges.remove(random_withdraw_bridge)
82 |
83 | for withdraw_bridge in withdraw_bridges:
84 | patterns.remove(withdraw_bridge)
85 |
86 | if 'okx_deposit' in patterns:
87 | patterns.remove('okx_deposit')
88 | patterns.append('okx_deposit')
89 |
90 | for pattern in patterns:
91 | task = create_task(process_task(private_key, pattern))
92 | tasks.append(task)
93 |
94 | await task
95 | time_to_sleep = random.randint(MIN_PAUSE, MAX_PAUSE)
96 | logger.info(f'Sleeping {time_to_sleep} seconds...')
97 | await sleep(time_to_sleep)
98 |
99 | await gather(*tasks)
100 |
101 |
102 | def start_event_loop(awaitable: Awaitable[None]) -> None:
103 | run(awaitable)
104 |
105 |
106 | if __name__ == '__main__':
107 | start_event_loop(main())
108 |
--------------------------------------------------------------------------------
/okx_data/okx_data.py:
--------------------------------------------------------------------------------
1 | API_KEY = ''
2 | SECRET_KEY = ''
3 | PASSPHRASE = ''
4 |
5 | USE_PROXY = True
6 |
7 | proxy = 'http:/login:pass@ip:port'
8 |
--------------------------------------------------------------------------------
/okx_data/okx_wallets.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nftscripts/scroll/c8cadeb3a914effba7a0fb3cb085a20a181aea16/okx_data/okx_wallets.txt
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.9.4
2 | ccxt==4.1.16
3 | colorama==0.4.6
4 | eth_abi==5.0.1
5 | eth_typing==3.5.0
6 | hexbytes==0.3.1
7 | loguru==0.7.2
8 | py_solc_x==1.1.1
9 | pyuseragents==1.0.5
10 | SQLAlchemy==2.0.21
11 | web3==6.7.0
--------------------------------------------------------------------------------
/src/database/data/analytics_data.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 | from sqlalchemy import func
3 |
4 | from src.database.models import (
5 | LiquidityTransaction,
6 | LendingTransaction,
7 | NFTTransaction,
8 | SwapTransaction,
9 | BridgeTransaction,
10 | DmailTransaction
11 | )
12 |
13 |
14 | class AnalyticData:
15 | def __init__(self, session, dex_name: str, wallet_address: str) -> None:
16 | self.session = session
17 | self.dex_name = dex_name
18 | self.wallet_address = wallet_address
19 |
20 | @property
21 | def interactions_data(
22 | self
23 | ) -> tuple[Optional[int], Optional[int], Optional[int], Optional[int], Optional[int], Optional[int]]:
24 | with self.session:
25 | liquidity_result = self.session.query(func.count().label('interactions')).filter(
26 | LiquidityTransaction.dex_name == self.dex_name,
27 | LiquidityTransaction.wallet_address == self.wallet_address
28 | ).first()
29 | swap_result = self.session.query(func.count().label('interactions')).filter(
30 | SwapTransaction.dex_name == self.dex_name,
31 | SwapTransaction.wallet_address == self.wallet_address
32 | ).first()
33 | bridge_result = self.session.query(func.count().label('interactions')).filter(
34 | BridgeTransaction.dex_name == self.dex_name,
35 | BridgeTransaction.wallet_address == self.wallet_address
36 | ).first()
37 | dmail_result = self.session.query(func.count().label('interactions')).filter(
38 | DmailTransaction.wallet_address == self.wallet_address
39 | ).first()
40 | nft_result = self.session.query(func.count().label('interactions')).filter(
41 | NFTTransaction.nft_name == self.dex_name,
42 | NFTTransaction.wallet_address == self.wallet_address
43 | ).first()
44 | lending_result = self.session.query(func.count().label('interactions')).filter(
45 | LendingTransaction.dex_name == self.dex_name,
46 | LendingTransaction.wallet_address == self.wallet_address
47 | ).first()
48 |
49 | return swap_result[0], liquidity_result[0], bridge_result[0], dmail_result[0], nft_result[0], \
50 | lending_result[0]
51 |
52 | @property
53 | def volume_data(self) -> tuple[Optional[int], Optional[int], Optional[int], Optional[int]]:
54 | with self.session:
55 | swap_volume = self.session.query(func.sum(SwapTransaction.amount).label('total_volume')).filter(
56 | SwapTransaction.dex_name == self.dex_name,
57 | SwapTransaction.wallet_address == self.wallet_address
58 | ).first()
59 | liquidity_volume = self.session.query(func.sum(LiquidityTransaction.amount).label('total_volume')).filter(
60 | LiquidityTransaction.dex_name == self.dex_name,
61 | LiquidityTransaction.wallet_address == self.wallet_address
62 | ).first()
63 | bridge_volume = self.session.query(func.sum(BridgeTransaction.amount).label('total_volume')).filter(
64 | BridgeTransaction.dex_name == self.dex_name,
65 | BridgeTransaction.wallet_address == self.wallet_address
66 | ).first()
67 | lending_volume = self.session.query(func.sum(LendingTransaction.amount).label('total_volume')).filter(
68 | LendingTransaction.dex_name == self.dex_name,
69 | LendingTransaction.wallet_address == self.wallet_address
70 | ).first()
71 | return swap_volume[0], liquidity_volume[0], bridge_volume[0], lending_volume[0]
72 |
--------------------------------------------------------------------------------
/src/database/models.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.ext.declarative import declarative_base
2 |
3 | from sqlalchemy import (
4 | create_engine,
5 | Sequence,
6 | Integer,
7 | Column,
8 | String,
9 | Float,
10 | )
11 |
12 | Base = declarative_base()
13 |
14 |
15 | class BridgeTransaction(Base):
16 | __tablename__ = 'bridge_transactions'
17 | id = Column(Integer, Sequence('bridge_transaction_id_seq'), primary_key=True)
18 | wallet_address = Column(String)
19 | tx_hash = Column(String)
20 | dex_name = Column(String)
21 | token = Column(String)
22 | amount = Column(Float)
23 |
24 |
25 | class SwapTransaction(Base):
26 | __tablename__ = 'swap_transactions'
27 | id = Column(Integer, Sequence('swap_transaction_id_seq'), primary_key=True)
28 | wallet_address = Column(String)
29 | tx_hash = Column(String)
30 | dex_name = Column(String)
31 | from_token = Column(String)
32 | to_token = Column(String)
33 | amount = Column(Float)
34 |
35 |
36 | class LiquidityTransaction(Base):
37 | __tablename__ = 'liquidity_transactions'
38 | id = Column(Integer, Sequence('liquidity_transaction_id_seq'), primary_key=True)
39 | wallet_address = Column(String)
40 | tx_hash = Column(String)
41 | dex_name = Column(String)
42 | token = Column(String)
43 | token2 = Column(String)
44 | amount = Column(Float)
45 |
46 |
47 | class NFTTransaction(Base):
48 | __tablename__ = 'nft_transactions'
49 | id = Column(Integer, Sequence('nft_transaction_id_seq'), primary_key=True)
50 | nft_name = Column(String)
51 | wallet_address = Column(String)
52 | tx_hash = Column(String)
53 | amount = Column(Float)
54 |
55 |
56 | class DmailTransaction(Base):
57 | __tablename__ = 'dmail_transactions'
58 | id = Column(Integer, Sequence('dmail_transaction_id_seq'), primary_key=True)
59 | wallet_address = Column(String)
60 | tx_hash = Column(String)
61 | dex_name = Column(String)
62 |
63 |
64 | class LendingTransaction(Base):
65 | __tablename__ = 'lending_transactions'
66 | id = Column(Integer, Sequence('lending_transaction_id_seq'), primary_key=True)
67 | dex_name = Column(String)
68 | wallet_address = Column(String)
69 | tx_hash = Column(String)
70 | amount = Column(Float)
71 |
72 |
73 | class Analytics(Base):
74 | __tablename__ = 'analytics'
75 | id = Column(String, primary_key=True)
76 | wallet_address = Column(String)
77 | dex_name = Column(String)
78 | interactions = Column(Integer, default=0)
79 | total_volume = Column(Float)
80 |
81 |
82 | engine = create_engine('sqlite:///transactions.db')
83 | Base.metadata.create_all(engine)
84 |
--------------------------------------------------------------------------------
/src/database/utils.py:
--------------------------------------------------------------------------------
1 | from asyncio import sleep
2 | import types
3 |
4 | from typing import (
5 | Optional,
6 | Type,
7 | )
8 |
9 | from sqlalchemy.orm import sessionmaker
10 | from loguru import logger
11 |
12 | from eth_typing import (
13 | Address,
14 | HexStr,
15 | )
16 |
17 | from src.database.data.analytics_data import AnalyticData
18 |
19 | from src.database.models import (
20 | LiquidityTransaction,
21 | LendingTransaction,
22 | BridgeTransaction,
23 | DmailTransaction,
24 | SwapTransaction,
25 | NFTTransaction,
26 | Analytics,
27 | engine,
28 | )
29 |
30 |
31 | class DataBaseUtils:
32 | SWAP_ACTION: str = 'swap'
33 | LIQUIDITY_ACTION: str = 'liquidity'
34 | MINT_ACTION: str = 'mint'
35 | BRIDGE_ACTION: str = 'bridge'
36 | DMAIL_ACTION: str = 'dmail'
37 | LENDING_ACTION: str = 'lending'
38 |
39 | def __init__(self, action: str) -> None:
40 | self.__action = action
41 | self.__session = sessionmaker(bind=engine)()
42 |
43 | if self.__action == self.SWAP_ACTION:
44 | self.__table_object = SwapTransaction
45 | elif self.__action == self.LIQUIDITY_ACTION:
46 | self.__table_object = LiquidityTransaction
47 | elif self.__action == self.MINT_ACTION:
48 | self.__table_object = NFTTransaction
49 | elif self.__action == self.BRIDGE_ACTION:
50 | self.__table_object = BridgeTransaction
51 | elif self.__action == self.DMAIL_ACTION:
52 | self.__table_object = DmailTransaction
53 | elif self.__action == self.LENDING_ACTION:
54 | self.__table_object = LendingTransaction
55 | else:
56 | raise ValueError()
57 |
58 | def __enter__(self) -> None:
59 | return self
60 |
61 | def __exit__(self,
62 | exc_type: Optional[Type[BaseException]],
63 | exc_value: Optional[BaseException],
64 | traceback: Optional[types.TracebackType]) -> None:
65 | self.__session.close()
66 |
67 | async def add_to_db(self, wallet_address: Address, tx_hash: HexStr, dex_name: str, amount: Optional[float] = None,
68 | from_token: Optional[str] = None, to_token: Optional[str] = None) -> None:
69 | transaction = self.__table_object(
70 | wallet_address=wallet_address,
71 | tx_hash=tx_hash,
72 | )
73 |
74 | if self.__action == self.SWAP_ACTION:
75 | transaction.dex_name = dex_name
76 | transaction.from_token = from_token
77 | transaction.to_token = to_token
78 | transaction.amount = amount
79 | elif self.__action == self.LIQUIDITY_ACTION:
80 | transaction.token = from_token
81 | transaction.token2 = to_token
82 | transaction.dex_name = dex_name
83 | transaction.amount = amount
84 | elif self.__action == self.MINT_ACTION:
85 | transaction.nft_name = dex_name
86 | elif self.__action == self.BRIDGE_ACTION:
87 | transaction.dex_name = dex_name
88 | transaction.token = 'ETH'
89 | transaction.amount = amount
90 | elif self.__action == self.DMAIL_ACTION:
91 | transaction.dex_name = dex_name
92 | elif self.__action == self.LENDING_ACTION:
93 | transaction.dex_name = dex_name
94 | transaction.amount = amount
95 |
96 | self.__session.add(transaction)
97 | self.__session.commit()
98 | self.__session.close()
99 | logger.success('✔️ | Successfully added to DataBase')
100 | await sleep(3)
101 | logger.debug('🔄 | Updating «analytics» table...')
102 | await sleep(3)
103 | self._update_analytics(dex_name, wallet_address)
104 | logger.success('🆕 | Information successfully updated')
105 |
106 | def _update_analytics(self, dex_name: str, wallet_address: Address) -> None:
107 | analytic_data = AnalyticData(self.__session, dex_name, wallet_address)
108 | swap_interactions, liquidity_interactions, bridge_interactions, \
109 | dmail_interactions, nft_interactions, lending_interactions = analytic_data.interactions_data
110 | swap_volume, liquidity_volume, bridge_volume, lending_volume = analytic_data.volume_data
111 | interactions = \
112 | liquidity_interactions + swap_interactions + bridge_interactions + dmail_interactions + nft_interactions \
113 | + lending_interactions
114 |
115 | if swap_volume is None:
116 | swap_volume = 0
117 | if liquidity_volume is None:
118 | liquidity_volume = 0
119 | if bridge_volume is None:
120 | bridge_volume = 0
121 | if lending_volume is None:
122 | lending_volume = 0
123 |
124 | total_volume = swap_volume + liquidity_volume + bridge_volume + lending_volume
125 |
126 | analytics_entry = self.__session.query(Analytics).filter_by(dex_name=dex_name,
127 | wallet_address=wallet_address).first()
128 | if analytics_entry:
129 | analytics_entry.interactions = interactions
130 | analytics_entry.total_volume = total_volume
131 | else:
132 | unique_id = str(hash(wallet_address) + hash(dex_name))
133 | analytics_entry = Analytics(id=unique_id, wallet_address=wallet_address, dex_name=dex_name,
134 | interactions=interactions, total_volume=total_volume)
135 | self.__session.add(analytics_entry)
136 |
137 | self.__session.commit()
138 |
--------------------------------------------------------------------------------
/src/modules/bridges/main_bridge/main_bridge.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | from src.modules.bridges.main_bridge.utils.transaction_data import create_bridge_tx
8 | from src.utils.data.chains import chain_mapping
9 | from src.utils.data.chains import ETH, SCROLL
10 | from src.utils.base_bridge import BaseBridge
11 | from src.utils.data.types import Types
12 |
13 |
14 | class MainBridge(BaseBridge):
15 | def __init__(self, private_key: str, action: str, amount: Union[float, List[float]], use_percentage: bool,
16 | bridge_percentage: Union[float, List[float]], claim_eth: bool) -> None:
17 |
18 | dex_name = 'MainBridge'
19 | if action.lower() == 'deposit':
20 | rpc = ETH.rpc
21 | contract_address = '0x6774bcbd5cecef1336b5300fb5186a12ddd8b367'
22 | abi_name = 'main_bridge'
23 | scan = chain_mapping['eth'].scan
24 | from_chain = 'ETH'
25 | to_chain = 'SCROLL'
26 | elif action.lower() == 'withdraw':
27 | rpc = SCROLL.rpc
28 | contract_address = '0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79'
29 | abi_name = 'main_bridge_scroll'
30 | scan = chain_mapping['scroll'].scan
31 | from_chain = 'SCROLL'
32 | to_chain = 'ETH'
33 | else:
34 | raise ValueError(f'Action must be deposit/withdraw only. Got {action}.')
35 | super().__init__(private_key, amount, use_percentage, bridge_percentage, contract_address, abi_name, dex_name,
36 | rpc, scan, from_chain, to_chain, claim_eth=claim_eth)
37 |
38 | def __repr__(self) -> str:
39 | return f'Ⓜ️ | {self.__class__.__name__}: {self.account_address}'
40 |
41 | def create_bridge_tx(self, contract: Contract, amount: int, web3: Web3, account_address: Address
42 | ) -> Types.BridgeTransaction:
43 | return create_bridge_tx(contract, amount, web3, account_address)
44 |
45 | def check_eligibility(self, amount: int) -> tuple[bool, None, None]:
46 | return True, None, None
47 |
--------------------------------------------------------------------------------
/src/modules/bridges/main_bridge/utils/data/proof_data/request_data.py:
--------------------------------------------------------------------------------
1 | import pyuseragents
2 |
3 |
4 | headers = {
5 | 'authority': 'mainnet-api-bridge.scroll.io',
6 | 'accept': '*/*',
7 | 'accept-language': 'ru,en;q=0.9,ru-RU;q=0.8,en-US;q=0.7',
8 | 'content-type': 'application/json',
9 | 'origin': 'https://scroll.io',
10 | 'referer': 'https://scroll.io/',
11 | 'sec-ch-ua': '"Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"',
12 | 'sec-ch-ua-mobile': '?0',
13 | 'sec-ch-ua-platform': '"Windows"',
14 | 'sec-fetch-dest': 'empty',
15 | 'sec-fetch-mode': 'cors',
16 | 'sec-fetch-site': 'same-site',
17 | 'user-agent': pyuseragents.random(),
18 | }
19 |
--------------------------------------------------------------------------------
/src/modules/bridges/main_bridge/utils/data/proof_data/txsbyhashes.py:
--------------------------------------------------------------------------------
1 | from aiohttp import ClientSession
2 | from asyncio import sleep
3 | from src.modules.bridges.main_bridge.utils.data.proof_data.request_data import headers
4 | from loguru import logger
5 |
6 |
7 | async def get_proof_data(tx_hash: str) -> tuple[int, int, str, str, str]:
8 | async with ClientSession(headers=headers) as session:
9 | json_data = {
10 | 'txs': [
11 | tx_hash,
12 | ],
13 | }
14 | while True:
15 | response = await session.post(url='https://mainnet-api-bridge.scroll.io/api/txsbyhashes', json=json_data)
16 | response_text = await response.json()
17 | data = response_text['data']['result']
18 | for information in data:
19 | amount = int(information['amount'])
20 | nonce = int(information['claimInfo']['nonce'])
21 | message = information['claimInfo']['message']
22 | batch_index = int(information['claimInfo']['batch_index'])
23 | proof = information['claimInfo']['proof']
24 | if proof == '0x':
25 | logger.info(f'Claim transaction is not ready yet..')
26 | await sleep(150)
27 | continue
28 | break
29 |
30 | return amount, nonce, message, batch_index, proof
31 |
--------------------------------------------------------------------------------
/src/modules/bridges/main_bridge/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from asyncio import sleep
2 |
3 | from web3.contract import Contract
4 | from web3.types import TxParams
5 | from eth_typing import Address
6 | from loguru import logger
7 | from web3 import Web3
8 |
9 | from src.modules.bridges.main_bridge.utils.data.proof_data.txsbyhashes import get_proof_data
10 | from src.utils.data.chains import ETH
11 | from src.utils.user.utils import Utils
12 |
13 |
14 | def create_bridge_tx(contract: Contract, amount: int, web3: Web3, account_address: Address) -> TxParams:
15 | if contract.address == web3.to_checksum_address('0x6774bcbd5cecef1336b5300fb5186a12ddd8b367'):
16 | utils = Utils()
17 | oracle_contract = utils.load_contract(
18 | '0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B',
19 | web3,
20 | 'oracle'
21 | )
22 | fee = oracle_contract.functions.estimateCrossDomainMessageFee(168000).call()
23 |
24 | tx = contract.functions.sendMessage(
25 | account_address,
26 | amount,
27 | "0x",
28 | 168000
29 | ).build_transaction({
30 | 'value': amount + fee,
31 | 'nonce': web3.eth.get_transaction_count(account_address),
32 | 'from': account_address,
33 | "gasPrice": web3.eth.gas_price,
34 | })
35 | elif contract.address == web3.to_checksum_address('0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79'):
36 | tx = contract.functions.withdrawETH(
37 | amount,
38 | 0
39 | ).build_transaction({
40 | 'value': amount,
41 | 'nonce': web3.eth.get_transaction_count(account_address),
42 | 'from': account_address,
43 | "gasPrice": web3.eth.gas_price,
44 | })
45 | else:
46 | logger.error(f'Unknown error')
47 | return
48 | return tx
49 |
50 |
51 | async def claim_eth(tx_hash: str, private_key: str) -> None:
52 | web3 = Web3(Web3.HTTPProvider(ETH.rpc))
53 | account = web3.eth.account.from_key(private_key)
54 | account_address = account.address
55 |
56 | contract = web3.eth.contract(Web3.to_checksum_address('0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367'),
57 | abi=Utils.load_abi('eth_claim'))
58 |
59 | while True:
60 | try:
61 | amount, nonce, message, batch_index, proof = await get_proof_data(tx_hash)
62 | break
63 | except Exception as ex:
64 | logger.error(f'Transaction is not ready yet | {ex}')
65 | await sleep(120)
66 |
67 | tx = contract.functions.relayMessageWithProof(
68 | Web3.to_checksum_address('0x6EA73e05AdC79974B931123675ea8F78FfdacDF0'),
69 | Web3.to_checksum_address('0x7F2b8C31F88B6006c382775eea88297Ec1e3E905'),
70 | amount,
71 | nonce,
72 | message,
73 | [batch_index, proof]
74 | ).build_transaction({
75 | 'value': 0,
76 | 'nonce': web3.eth.get_transaction_count(account_address),
77 | 'from': account_address,
78 | "gasPrice": web3.eth.gas_price,
79 | })
80 | while True:
81 | try:
82 | signed_tx = web3.eth.account.sign_transaction(tx, private_key)
83 | raw_tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
84 | tx_hash = web3.to_hex(raw_tx_hash)
85 | logger.success(f'Successfully claimed {amount / 10 ** 18} ETH | TX: https://etherscan.io/tx/{tx_hash}')
86 | except Exception as ex:
87 | if 'not ready' in str(ex):
88 | logger.error('Claim transaction is not ready yet...')
89 | await sleep(150)
90 | continue
91 | else:
92 | logger.error(ex)
93 | break
94 |
--------------------------------------------------------------------------------
/src/modules/bridges/orbiter/oribter_bridge.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from loguru import logger
6 | from web3 import Web3
7 |
8 | from src.modules.bridges.orbiter.utils.transaction_data import create_bridge_tx
9 | from src.utils.data.chains import chain_mapping
10 | from src.utils.base_bridge import BaseBridge
11 | from src.utils.data.types import Types
12 |
13 |
14 | class OrbiterBridge(BaseBridge):
15 | def __init__(self, private_key: str, amount: Union[float, List[float]], use_percentage: bool,
16 | bridge_percentage: Union[float, List[float]], from_chain: str, to_chain: str) -> None:
17 | dex_name = 'Orbiter'
18 | scan = chain_mapping[from_chain.lower()].scan
19 | rpc = chain_mapping[from_chain.lower()].rpc
20 | orbiter_codes = {
21 | "eth": 9001,
22 | "arb": 9002,
23 | "op": 9007,
24 | "era": 9014,
25 | "base": 9021,
26 | "scroll": 9019,
27 | "linea": 9023
28 | }
29 | code = orbiter_codes[to_chain.lower()]
30 | if use_percentage is False:
31 | if isinstance(amount, float):
32 | if not 0.005 < amount < 5:
33 | logger.error(f'Limits error. 0.005 < amount < 5. Got {amount}')
34 | return
35 | elif isinstance(amount, List):
36 | if not (amount[0] > 0.005 and amount[1] < 5):
37 | logger.error(f'Limits error. 0.0035 < amount < 0.2. Got {amount}')
38 | return
39 | else:
40 | logger.error(f'amount must be List or float. Got {type(amount)}')
41 | return
42 |
43 | super().__init__(private_key, amount, use_percentage, bridge_percentage, contract_address=None, abi_name=None,
44 | dex_name=dex_name, rpc=rpc, scan=scan, from_chain=from_chain, to_chain=to_chain, code=code)
45 |
46 | def __repr__(self) -> str:
47 | return f'🛸 | {self.__class__.__name__}: {self.account_address} | {self.from_chain} => {self.to_chain}'
48 |
49 | def create_bridge_tx(self, contract: Contract, amount: int, web3: Web3, account_address: Address
50 | ) -> Types.BridgeTransaction:
51 | return create_bridge_tx(amount, web3, account_address)
52 |
53 | def check_eligibility(self, amount: int) -> tuple[bool, Union[float, None], Union[int, None]]:
54 | min_limit = 0.005
55 | max_limit = 5
56 |
57 | if min_limit < amount / 10 ** 18 < max_limit:
58 | return True, None, None
59 | return True, min_limit, max_limit
60 |
--------------------------------------------------------------------------------
/src/modules/bridges/orbiter/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from web3.types import TxParams
2 | from eth_typing import Address
3 | from web3 import Web3
4 |
5 |
6 | def create_bridge_tx(amount: int, web3: Web3, account_address: Address) -> TxParams:
7 | return {
8 | 'chainId': web3.eth.chain_id,
9 | 'from': account_address,
10 | 'to': web3.to_checksum_address('0x80c67432656d59144ceff962e8faf8926599bcf8'),
11 | 'value': amount,
12 | 'nonce': web3.eth.get_transaction_count(account_address),
13 | "gasPrice": web3.eth.gas_price,
14 | }
15 |
--------------------------------------------------------------------------------
/src/modules/bridges/owlto/owlto_bridge.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from loguru import logger
6 | from web3 import Web3
7 |
8 | from src.modules.bridges.owlto.utils.transaction_data import create_bridge_tx
9 | from src.utils.data.chains import chain_mapping
10 | from src.utils.base_bridge import BaseBridge
11 | from src.utils.data.types import Types
12 |
13 |
14 | class OwlBridge(BaseBridge):
15 | def __init__(self, private_key: str, amount: Union[float, List[float]], use_percentage: bool,
16 | bridge_percentage: Union[float, List[float]], from_chain: str, to_chain: str) -> None:
17 | dex_name = 'Owlto'
18 | scan = chain_mapping[from_chain.lower()].scan
19 | rpc = chain_mapping[from_chain.lower()].rpc
20 | owlto_codes = {
21 | 'scroll': '0006',
22 | 'era': '0002',
23 | 'base': '0012',
24 | 'linea': '0007',
25 | 'arb': '0004',
26 | 'op': '0003',
27 | 'eth': '0001'
28 | }
29 | code = owlto_codes[to_chain.lower()]
30 | if use_percentage is False:
31 | if isinstance(amount, float):
32 | if not 0.0035 < amount < 0.2:
33 | logger.error(f'Limits error. 0.0035 < amount < 0.2. Got {amount}')
34 | return
35 | elif isinstance(amount, List):
36 | if not (amount[0] > 0.0035 and amount[1] < 0.2):
37 | logger.error(f'Limits error. 0.0035 < amount < 0.2. Got {amount}')
38 | return
39 | else:
40 | logger.error(f'amount must be List or float. Got {type(amount)}')
41 | return
42 |
43 | super().__init__(private_key, amount, use_percentage, bridge_percentage, contract_address=None, abi_name=None,
44 | dex_name=dex_name, rpc=rpc, scan=scan, from_chain=from_chain, to_chain=to_chain, code=code)
45 |
46 | def __repr__(self) -> str:
47 | return f'🦉 | {self.__class__.__name__}: {self.account_address} | {self.from_chain} => {self.to_chain}'
48 |
49 | def create_bridge_tx(self, contract: Contract, amount: int, web3: Web3, account_address: Address
50 | ) -> Types.BridgeTransaction:
51 | return create_bridge_tx(amount, web3, account_address)
52 |
53 | def check_eligibility(self, amount: int) -> tuple[bool, Union[float, None], Union[float, None]]:
54 | min_limit = 0.0035
55 | max_limit = 0.2
56 |
57 | if min_limit < amount / 10 ** 18 < max_limit:
58 | return True, None, None
59 | return False, min_limit, max_limit
60 |
--------------------------------------------------------------------------------
/src/modules/bridges/owlto/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from web3.types import TxParams
2 | from eth_typing import Address
3 | from web3 import Web3
4 |
5 |
6 | def create_bridge_tx(amount: int, web3: Web3, account_address: Address) -> TxParams:
7 | return {
8 | 'chainId': web3.eth.chain_id,
9 | 'from': account_address,
10 | 'to': web3.to_checksum_address('0x5e809a85aa182a9921edd10a4163745bb3e36284'),
11 | 'value': amount,
12 | 'nonce': web3.eth.get_transaction_count(account_address),
13 | "gasPrice": web3.eth.gas_price,
14 | }
15 |
--------------------------------------------------------------------------------
/src/modules/deploy/contract/contract.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.8.0;
2 |
3 | contract SimpleStorage {
4 | uint256 private storedData;
5 |
6 | function set(uint256 x) public {
7 | storedData = x;
8 | }
9 |
10 | function get() public view returns (uint256) {
11 | return storedData;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/modules/deploy/contract_deployer.py:
--------------------------------------------------------------------------------
1 | from src.utils.user.account import Account
2 |
3 | from src.modules.deploy.utils.data_exctract import (
4 | get_bytecode,
5 | get_abi,
6 | compile_contract,
7 | )
8 |
9 |
10 | class Deployer(Account):
11 | def __init__(self, private_key: str, use_0x_bytecode: bool):
12 | self.use_0x_bytecode = use_0x_bytecode
13 | super().__init__(private_key)
14 |
15 | def __repr__(self) -> str:
16 | return f'Deploying contract for address [{self.account_address}]'
17 |
18 | def deploy(self) -> None:
19 | if not self.use_0x_bytecode:
20 | compile_contract()
21 | abi = get_abi()
22 | bytecode = get_bytecode()
23 | else:
24 | abi = self.load_abi('deploy')
25 | bytecode = '0x'
26 |
27 | contract = self.web3.eth.contract(
28 | abi=abi,
29 | bytecode=bytecode
30 | )
31 |
32 | tx = contract.constructor().build_transaction({
33 | 'value': 0,
34 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
35 | 'from': self.account_address,
36 | 'gasPrice': 0,
37 | 'gas': 0
38 | })
39 | tx.update({'gasPrice': self.web3.eth.gas_price})
40 | gas_limit = self.web3.eth.estimate_gas(tx)
41 | tx.update({'gas': gas_limit})
42 |
43 | tx_hash = self.sign_transaction(tx)
44 |
45 | self.logger.success(
46 | f'Successfully deployed contract for address [{self.account_address}] | TX: https://blockscout.scroll.io/tx/{tx_hash}'
47 | )
48 |
--------------------------------------------------------------------------------
/src/modules/deploy/utils/data_exctract.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from solcx import (
4 | compile_standard,
5 | install_solc,
6 | )
7 |
8 |
9 | def compile_contract() -> None:
10 | install_solc('0.8.0')
11 | with open('src/modules/deploy/contract/contract.sol', 'r') as file:
12 | contract = file.read()
13 |
14 | compiled_sol = compile_standard(
15 | {
16 | "language": "Solidity",
17 | "sources": {"contract.sol": {"content": contract}},
18 | "settings": {
19 | "outputSelection": {
20 | "*": {
21 | "*": ["abi", "metadata", "evm.bytecode", "evm.bytecode.sourceMap"]
22 | }
23 | }
24 | },
25 | },
26 | solc_version="0.8.0",
27 | )
28 |
29 | with open("compiled_code.json", "w") as file:
30 | json.dump(compiled_sol, file)
31 |
32 |
33 | def get_bytecode() -> str:
34 | with open('compiled_code.json', 'r') as file:
35 | compiled_sol = json.load(file)
36 |
37 | bytecode = compiled_sol["contracts"]["contract.sol"]["SimpleStorage"]["evm"][
38 | "bytecode"
39 | ]["object"]
40 | return bytecode
41 |
42 |
43 | def get_abi() -> str:
44 | with open('compiled_code.json', 'r') as file:
45 | compiled_sol = json.load(file)
46 |
47 | abi = json.loads(
48 | compiled_sol["contracts"]["contract.sol"]["SimpleStorage"]["metadata"]
49 | )["output"]["abi"]
50 | return abi
51 |
--------------------------------------------------------------------------------
/src/modules/dmail/dmail.py:
--------------------------------------------------------------------------------
1 | import random
2 | from hashlib import sha256
3 |
4 | from web3 import Web3
5 |
6 | from src.utils.data.contracts import (
7 | contracts,
8 | abi_names,
9 | )
10 | from src.utils.wrappers.decorators import retry
11 | from src.utils.user.account import Account
12 | from src.database.utils import DataBaseUtils
13 | from config import USE_DATABASE
14 |
15 |
16 | class Dmail(Account):
17 | def __init__(self, private_key: str) -> None:
18 | self.contract_address = contracts['dmail']
19 | self.abi_name = abi_names['dmail']
20 | super().__init__(private_key=private_key)
21 | self.db_utils = DataBaseUtils('dmail')
22 |
23 | def __repr__(self) -> str:
24 | return f'{self.account_address} | Sending mail...'
25 |
26 | @retry()
27 | async def send_mail(self):
28 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
29 | email = sha256(str(1e11 * random.random()).encode()).hexdigest()
30 | theme = sha256(str(1e11 * random.random()).encode()).hexdigest()
31 |
32 | data = contract.encodeABI("send_mail", args=(email, theme))
33 |
34 | tx = {
35 | 'chainId': self.web3.eth.chain_id,
36 | 'from': self.account_address,
37 | 'to': Web3.to_checksum_address(self.contract_address),
38 | 'data': data,
39 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
40 | 'gasPrice': self.web3.eth.gas_price,
41 | 'gas': 0
42 | }
43 |
44 | gas_limit = self.web3.eth.estimate_gas(tx)
45 | tx.update({'gas': gas_limit})
46 |
47 | tx_hash = self.sign_transaction(tx)
48 | self.wait_until_tx_finished(tx_hash)
49 | if USE_DATABASE:
50 | await self.db_utils.add_to_db(self.account_address, tx_hash, 'Dmail')
51 |
--------------------------------------------------------------------------------
/src/modules/lendings/aave/aave.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | from typing import (
4 | Union,
5 | List,
6 | )
7 |
8 | from src.database.utils import DataBaseUtils
9 | from src.utils.user.account import Account
10 | from src.utils.wrappers.decorators import retry
11 | from src.utils.data.contracts import contracts, abi_names
12 |
13 |
14 | class Aave(Account):
15 | def __init__(self, private_key: str, amount: Union[float, List[float]], use_percentage: bool,
16 | deposit_percentage: Union[float, List[float]], remove_percentage: Union[float, List[float]],
17 | remove_all: bool) -> None:
18 | self.private_key = private_key
19 |
20 | super().__init__(private_key)
21 |
22 | if isinstance(amount, List):
23 | self.amount = random.uniform(amount[0], amount[1])
24 | elif isinstance(amount, float):
25 | self.amount = amount
26 | else:
27 | self.logger.error(f'amount must be list[float] or float. Got {type(amount)}')
28 | return
29 | self.use_percentage = use_percentage
30 |
31 | if isinstance(deposit_percentage, List):
32 | self.deposit_percentage = random.uniform(deposit_percentage[0], deposit_percentage[1])
33 | elif isinstance(deposit_percentage, float):
34 | self.deposit_percentage = deposit_percentage
35 | else:
36 | self.logger.error(f'amount must be list[float] or float. Got {type(deposit_percentage)}')
37 | return
38 |
39 | if isinstance(remove_percentage, List):
40 | self.remove_percentage = random.uniform(remove_percentage[0], remove_percentage[1])
41 | elif isinstance(remove_percentage, float):
42 | self.remove_percentage = remove_percentage
43 | else:
44 | self.logger.error(f'amount must be list[float] or float. Got {type(remove_percentage)}')
45 | return
46 |
47 | self.remove_all = remove_all
48 | self.db_utils = DataBaseUtils('lending')
49 |
50 | def __repr__(self) -> str:
51 | return f'{self.__class__.__name__} | [{self.account_address}]'
52 |
53 | async def get_deposit_amount(self):
54 | aave_weth_contract = self.load_contract(contracts['aave']['aave_weth'], self.web3, 'erc20')
55 |
56 | amount = aave_weth_contract.functions.balanceOf(self.account_address).call()
57 |
58 | return amount
59 |
60 | @retry()
61 | async def deposit(self) -> None:
62 | contract = self.load_contract(contracts['aave']['aave_contract'], self.web3, abi_names['aave'])
63 | amount = int(self.amount * 10 ** 18)
64 | balance = self.get_wallet_balance('ETH', '...')
65 | if self.use_percentage:
66 | amount = int(balance * self.deposit_percentage)
67 |
68 | if amount > balance:
69 | self.logger.error(f'Not enough balance for wallet | [{self.account_address}]')
70 | return
71 |
72 | tx = contract.functions.depositETH(
73 | self.web3.to_checksum_address("0x11fCfe756c05AD438e312a7fd934381537D3cFfe"),
74 | self.account_address,
75 | 0
76 | ).build_transaction({
77 | 'value': amount,
78 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
79 | 'from': self.account_address,
80 | "gasPrice": self.web3.eth.gas_price
81 | })
82 | self.logger.info(f"[{self.account_address}] deposit on Aave | {amount / 10 ** 18} ETH")
83 |
84 | tx_hash = self.sign_transaction(tx)
85 | confirmed = self.wait_until_tx_finished(tx_hash)
86 |
87 | if confirmed:
88 | self.logger.success(
89 | f'Successfully deposited {amount / 10 ** 18} ETH | TX: https://scrollscan.com/tx/{tx_hash}')
90 |
91 | @retry()
92 | async def withdraw(self) -> Union[str, bool]:
93 | contract = self.load_contract(contracts['aave']['aave_contract'], self.web3, abi_names['aave'])
94 | deposited_amount = await self.get_deposit_amount()
95 | amount = int(self.amount * 10 ** 18)
96 | if deposited_amount <= (0.000000001 * 10 ** 18):
97 | self.logger.error(f'Your deposited amount is 0 | [{self.account_address}]')
98 | return 'ZeroBalance'
99 |
100 | if self.remove_all is True:
101 | amount = deposited_amount
102 | if self.use_percentage:
103 | amount = int(deposited_amount * self.remove_percentage)
104 |
105 | self.logger.info(
106 | f"[{self.account_address}] withdrawing from Aave | {amount / 10 ** 18} ETH"
107 | )
108 |
109 | await self.approve_token(
110 | amount,
111 | self.private_key,
112 | "0xf301805be1df81102c957f6d4ce29d2b8c056b2a",
113 | contracts['aave']['aave_contract'],
114 | self.account_address,
115 | self.web3
116 | )
117 |
118 | tx = contract.functions.withdrawETH(
119 | self.web3.to_checksum_address("0x11fCfe756c05AD438e312a7fd934381537D3cFfe"),
120 | amount,
121 | self.account_address
122 | ).build_transaction({
123 | 'value': 0,
124 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
125 | 'from': self.account_address,
126 | "gasPrice": self.web3.eth.gas_price
127 | })
128 |
129 | tx_hash = self.sign_transaction(tx)
130 | confirmed = self.wait_until_tx_finished(tx_hash)
131 |
132 | if confirmed:
133 | self.logger.success(
134 | f'Successfully withdrawn {amount / 10 ** 18} ETH | TX: https://scrollscan.com/tx/{tx_hash}')
135 | return True
136 | return False
137 |
--------------------------------------------------------------------------------
/src/modules/lendings/layerbank/layerbank.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 | import random
3 |
4 | from src.database.utils import DataBaseUtils
5 | from src.utils.user.account import Account
6 | from src.utils.data.tokens import tokens
7 | from config import USE_DATABASE
8 |
9 | from src.utils.data.contracts import (
10 | contracts,
11 | abi_names,
12 | )
13 |
14 |
15 | class LayerBankDeposit(Account):
16 | def __init__(self, private_key: str, amount: Union[float, List[float]], use_percentage: bool,
17 | percentage: Union[float, List[float]], only_collateral: bool) -> None:
18 |
19 | super().__init__(private_key=private_key)
20 |
21 | if isinstance(amount, List):
22 | self.amount = random.uniform(amount[0], amount[1])
23 | elif isinstance(amount, float):
24 | self.amount = amount
25 | else:
26 | self.logger.error(f'amount must be float or list[float]. Got {type(amount)}')
27 | return
28 |
29 | self.use_percentage = use_percentage
30 | if isinstance(percentage, List):
31 | self.percentage = random.uniform(percentage[0], percentage[1])
32 | elif isinstance(percentage, float):
33 | self.percentage = percentage
34 | else:
35 | self.logger.error(f'percentage must be float or list[float]. Got {type(percentage)}')
36 | return
37 |
38 | self.contract = self.load_contract(
39 | address=contracts['layerbank'],
40 | web3=self.web3,
41 | abi_name=abi_names['layerbank']
42 | )
43 | self.only_collateral = only_collateral
44 | self.db_utils = DataBaseUtils('lending')
45 |
46 | def __repr__(self) -> str:
47 | return f'{self.__class__.__name__} | [{self.account_address}]'
48 |
49 | async def deposit(self) -> None:
50 | balance = self.get_wallet_balance('ETH', tokens['ETH'])
51 |
52 | if balance == 0:
53 | self.logger.warning(f'Your balance is 0 | [{self.account_address}]')
54 | return
55 | if not self.only_collateral:
56 | if self.use_percentage:
57 | amount = int(balance * self.percentage)
58 | else:
59 | amount = int(self.amount * 10 ** 18)
60 | else:
61 | amount = 0
62 |
63 | if not self.only_collateral:
64 | tx = self.contract.functions.supply(
65 | self.web3.to_checksum_address('0x274C3795dadfEbf562932992bF241ae087e0a98C'),
66 | amount
67 | ).build_transaction({
68 | 'value': amount,
69 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
70 | 'from': self.account_address,
71 | "gasPrice": self.web3.eth.gas_price
72 | })
73 | else:
74 | txs = [self.contract.functions.enterMarkets(
75 | [self.web3.to_checksum_address('0x274C3795dadfEbf562932992bF241ae087e0a98C')]
76 | ), self.contract.functions.exitMarket(
77 | self.web3.to_checksum_address('0x274C3795dadfEbf562932992bF241ae087e0a98C')
78 | )]
79 | tx = random.choice(txs).build_transaction({
80 | 'value': amount,
81 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
82 | 'from': self.account_address,
83 | "gasPrice": self.web3.eth.gas_price
84 | })
85 |
86 | tx_hash = self.sign_transaction(tx)
87 | confirmed = self.wait_until_tx_finished(tx_hash)
88 |
89 | if confirmed:
90 | if not self.only_collateral:
91 | self.logger.success(
92 | f'Successfully deposited {amount / 10 ** 18} ETH | TX: https://blockscout.scroll.io/tx/{tx_hash}'
93 | )
94 | else:
95 | self.logger.success(
96 | f'Successfully used collateral | TX: https://blockscout.scroll.io/tx/{tx_hash}'
97 | )
98 | if USE_DATABASE:
99 | await self.db_utils.add_to_db(self.account_address, f'https://blockscout.scroll.io/tx/{tx_hash}',
100 | self.__class__.__name__, amount / 10 ** 18)
101 |
102 |
103 | class LayerBankWithdraw(Account):
104 | def __init__(self, private_key: str, amount: Union[float, List[float]], withdraw_all: bool, use_percentage: bool,
105 | percentage: Union[float, List[float]]) -> None:
106 |
107 | super().__init__(private_key=private_key)
108 |
109 | if isinstance(amount, List):
110 | self.amount = random.uniform(amount[0], amount[1])
111 | elif isinstance(amount, float):
112 | self.amount = amount
113 | else:
114 | self.logger.error(f'amount must be float or list[float]. Got {type(amount)}')
115 | return
116 |
117 | self.withdraw_all = withdraw_all
118 | self.use_percentage = use_percentage
119 | if withdraw_all is True and use_percentage is True:
120 | self.logger.warning(f'You are using withdraw_all and use_percentage both True. Using withdraw_all = True')
121 | if isinstance(percentage, List):
122 | self.percentage = random.uniform(percentage[0], percentage[1])
123 | elif isinstance(percentage, float):
124 | self.percentage = percentage
125 | else:
126 | self.logger.error(f'percentage must be float or list[float]. Got {type(percentage)}')
127 | return
128 |
129 | self.contract = self.load_contract(
130 | address=contracts['layerbank'],
131 | web3=self.web3,
132 | abi_name=abi_names['layerbank']
133 | )
134 | self.db_utils = DataBaseUtils('lending')
135 |
136 | def __repr__(self) -> str:
137 | return f'{self.__class__.__name__} | [{self.account_address}]'
138 |
139 | async def withdraw(self) -> Union[str, bool]:
140 | balance = self.get_wallet_balance('...', '0x274C3795dadfEbf562932992bF241ae087e0a98C')
141 |
142 | if balance == 0:
143 | self.logger.warning(f"You don't have any tokens to withdraw | [{self.account_address}]")
144 | return 'ZeroBalance'
145 |
146 | if self.use_percentage:
147 | amount = int(balance * self.percentage)
148 | else:
149 | amount = int(self.amount * 10 ** 18)
150 |
151 | if self.withdraw_all:
152 | amount = balance
153 |
154 | tx = self.contract.functions.redeemToken(
155 | self.web3.to_checksum_address('0x274C3795dadfEbf562932992bF241ae087e0a98C'),
156 | amount
157 | ).build_transaction({
158 | 'value': 0,
159 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
160 | 'from': self.account_address,
161 | "gasPrice": self.web3.eth.gas_price
162 | })
163 |
164 | tx_hash = self.sign_transaction(tx)
165 | confirmed = self.wait_until_tx_finished(tx_hash)
166 |
167 | if confirmed:
168 | self.logger.success(
169 | f'Successfully withdrawn {amount / 10 ** 18} ETH | TX: https://blockscout.scroll.io/tx/{tx_hash}'
170 | )
171 | if USE_DATABASE:
172 | await self.db_utils.add_to_db(self.account_address, f'https://blockscout.scroll.io/tx/{tx_hash}',
173 | self.__class__.__name__, amount / 10 ** 18)
174 |
175 | return True
176 | return False
177 |
--------------------------------------------------------------------------------
/src/modules/nft/l2pass/l2pass.py:
--------------------------------------------------------------------------------
1 | from web3.contract import Contract
2 |
3 | from src.utils.wrappers.decorators import retry
4 | from src.utils.user.account import Account
5 |
6 | from src.utils.data.contracts import (
7 | contracts,
8 | abi_names,
9 | )
10 |
11 |
12 | class L2Pass(Account):
13 | def __init__(self, private_key: str) -> None:
14 | super().__init__(private_key)
15 |
16 | def __str__(self) -> str:
17 | return f'[{self.account_address}] | Minting L2Pass NFT'
18 |
19 | @staticmethod
20 | def get_mint_price(contract: Contract) -> int:
21 | price = contract.functions.mintPrice().call()
22 |
23 | return price
24 |
25 | @retry()
26 | async def mint(self) -> None:
27 | contract = self.load_contract(contracts['l2pass'], self.web3, abi_names['l2pass'])
28 | price = self.get_mint_price(contract)
29 | tx = contract.functions.mint(1).build_transaction({
30 | 'value': price,
31 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
32 | 'from': self.account_address,
33 | "gasPrice": self.web3.eth.gas_price
34 | })
35 | tx_hash = self.sign_transaction(tx)
36 | self.wait_until_tx_finished(tx_hash)
37 |
--------------------------------------------------------------------------------
/src/modules/nft/omnisea/omnisea.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 |
4 | from src.utils.wrappers.decorators import retry
5 | from src.utils.user.account import Account
6 |
7 | from src.utils.data.contracts import (
8 | contracts,
9 | abi_names,
10 | )
11 |
12 |
13 | class Omnisea(Account):
14 | def __init__(self, private_key: str) -> None:
15 | super().__init__(private_key)
16 |
17 | def __str__(self) -> str:
18 | return f'[{self.account_address}] | Creating NFT on Omnisea'
19 |
20 | @staticmethod
21 | def generate_collection_data() -> tuple[str, str]:
22 | title = "".join(random.sample([chr(i) for i in range(97, 123)], random.randint(5, 15)))
23 | symbol = "".join(random.sample([chr(i) for i in range(65, 91)], random.randint(3, 6)))
24 | return title, symbol
25 |
26 | @retry()
27 | async def create(self) -> None:
28 | contract = self.load_contract(contracts['omnisea'], self.web3, abi_names['omnisea'])
29 | title, symbol = self.generate_collection_data()
30 |
31 | tx = contract.functions.create([
32 | title,
33 | symbol,
34 | "",
35 | "",
36 | 0,
37 | True,
38 | 0,
39 | int(time.time()) + 1000000]
40 | ).build_transaction({
41 | 'value': 0,
42 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
43 | 'from': self.account_address,
44 | "gasPrice": self.web3.eth.gas_price
45 | })
46 |
47 | tx_hash = self.sign_transaction(tx)
48 | self.wait_until_tx_finished(tx_hash)
49 |
--------------------------------------------------------------------------------
/src/modules/nft/scrollcitizen/scrollcitizen.py:
--------------------------------------------------------------------------------
1 | from web3.contract import Contract
2 | from web3.types import TxParams
3 |
4 | from src.utils.data.contracts import abi_names
5 | from src.utils.base_mint import BaseMint
6 |
7 |
8 | class ScrollCitizen(BaseMint):
9 | def __init__(self, private_key: str, contract_address: str) -> None:
10 | abi_name = abi_names['scroll_citizen']
11 | nft_name = 'ScrollCitizen'
12 | super().__init__(private_key, contract_address, abi_name, nft_name)
13 |
14 | def __repr__(self) -> str:
15 | return f'[{self.account_address}] | {self.__class__.__name__} Mint'
16 |
17 | def create_mint_tx(self, contract: Contract) -> TxParams:
18 | tx = contract.functions.mint(
19 | self.web3.to_checksum_address("0x08770dA8fE1541D771B77C9C997A0E4a085A6E59")
20 | ).build_transaction({
21 | 'value': int(0.0001 * 10 ** 18),
22 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
23 | 'from': self.account_address,
24 | "gasPrice": self.web3.eth.gas_price
25 | })
26 | return tx
27 |
--------------------------------------------------------------------------------
/src/modules/nft/zerius/utils/data.py:
--------------------------------------------------------------------------------
1 | from web3.contract import Contract
2 | from eth_typing import Address
3 | from web3 import Web3
4 |
5 |
6 | def get_l0_fee(contract: Contract, chain_id: str, nft_id: int, account_address: Address) -> int:
7 | fee = contract.functions.estimateSendFee(
8 | chain_id,
9 | account_address,
10 | nft_id,
11 | False,
12 | "0x"
13 | ).call()
14 |
15 | return int(fee[0] * 1.2)
16 |
17 |
18 | def get_nft_id(web3: Web3, tx_hash: str) -> int:
19 | receipts = web3.eth.get_transaction_receipt(tx_hash)
20 |
21 | nft_id = int(receipts["logs"][0]["topics"][-1].hex(), 0)
22 |
23 | return nft_id
24 |
--------------------------------------------------------------------------------
/src/modules/nft/zerius/zerius.py:
--------------------------------------------------------------------------------
1 | from asyncio import sleep
2 | import random
3 |
4 | from typing import (
5 | Union,
6 | List,
7 | )
8 |
9 | from eth_typing import HexStr
10 |
11 | from src.database.utils import DataBaseUtils
12 | from src.utils.user.account import Account
13 | from config import USE_DATABASE
14 |
15 | from src.modules.nft.zerius.utils.data import (
16 | get_l0_fee,
17 | get_nft_id,
18 | )
19 |
20 |
21 | class Zerius(Account):
22 | def __init__(self, private_key: str, chain_to_bridge: Union[str, List[str]]) -> None:
23 | super().__init__(private_key=private_key)
24 |
25 | self.contract = self.load_contract('0xeb22c3e221080ead305cae5f37f0753970d973cd', self.web3, 'zerius')
26 | self.chain_ids = {
27 | "arb": 110,
28 | "op": 111,
29 | "polygon": 109,
30 | "bsc": 102,
31 | "avax": 106,
32 | }
33 | if isinstance(chain_to_bridge, List):
34 | self.chain_to_bridge = random.choice(chain_to_bridge)
35 | elif isinstance(chain_to_bridge, str):
36 | self.chain_to_bridge = chain_to_bridge
37 | else:
38 | self.logger.error(f'chain_to_bridge must be str or List[str]. Got {type(chain_to_bridge)}')
39 | return
40 | self.chain_id = self.chain_ids[self.chain_to_bridge.lower()]
41 | self.db_utils = DataBaseUtils('mint')
42 |
43 | def __repr__(self) -> None:
44 | return f'{self.__class__.__name__} | {self.account_address}'
45 |
46 | def mint(self) -> HexStr:
47 | mint_fee = self.contract.functions.mintFee().call()
48 | tx = self.contract.functions.mint().build_transaction({
49 | 'from': self.account_address,
50 | 'value': mint_fee,
51 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
52 | "gasPrice": self.web3.eth.gas_price
53 | })
54 |
55 | tx_hash = self.sign_transaction(tx)
56 | confirmed = self.wait_until_tx_finished(tx_hash)
57 |
58 | if confirmed:
59 | self.logger.success(
60 | f'Successfully Minted NFT | TX: https://blockscout.scroll.io/tx/{tx_hash}'
61 | )
62 | return tx_hash
63 |
64 | async def bridge(self) -> None:
65 | mint_hash = self.mint()
66 |
67 | if not mint_hash:
68 | return
69 |
70 | await sleep(10)
71 | nft_id = get_nft_id(self.web3, mint_hash)
72 | random_sleep = random.randint(20, 30)
73 | self.logger.debug(f'Sleeping {random_sleep} seconds before bridge...')
74 | await sleep(random_sleep)
75 |
76 | l0_fee = get_l0_fee(self.contract, self.chain_id, nft_id, self.account_address)
77 | base_bridge_fee = self.contract.functions.bridgeFee().call()
78 |
79 | tx = self.contract.functions.sendFrom(
80 | self.account_address,
81 | self.chain_id,
82 | self.account_address,
83 | nft_id,
84 | '0x0000000000000000000000000000000000000000',
85 | '0x0000000000000000000000000000000000000000',
86 | '0x0001000000000000000000000000000000000000000000000000000000000003d090'
87 | ).build_transaction({
88 | 'from': self.account_address,
89 | 'value': l0_fee + base_bridge_fee,
90 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
91 | "gasPrice": self.web3.eth.gas_price
92 | })
93 |
94 | tx_hash = self.sign_transaction(tx)
95 | confirmed = self.wait_until_tx_finished(tx_hash)
96 |
97 | if confirmed:
98 | self.logger.success(
99 | f'Successfully Bridged NFT into {self.chain_to_bridge} | TX: https://blockscout.scroll.io/tx/{tx_hash}'
100 | )
101 |
102 | if USE_DATABASE:
103 | await self.db_utils.add_to_db(self.account_address, f'https://blockscout.scroll.io/tx/{tx_hash}', 'Zerius')
104 |
--------------------------------------------------------------------------------
/src/modules/nft/zkstars/zkstars.py:
--------------------------------------------------------------------------------
1 | from web3.contract import Contract
2 | from web3.types import TxParams
3 |
4 | from src.utils.data.contracts import abi_names
5 | from src.utils.base_mint import BaseMint
6 |
7 |
8 | class ZKStars(BaseMint):
9 | def __init__(self, private_key: str, contract_address: str) -> None:
10 | abi_name = abi_names['zkstars']
11 | nft_name = 'ZKStars'
12 | super().__init__(private_key, contract_address, abi_name, nft_name)
13 |
14 | def __repr__(self) -> str:
15 | return f'[{self.account_address}] | {self.__class__.__name__} Mint'
16 |
17 | def create_mint_tx(self, contract: Contract) -> TxParams:
18 | mint_price = contract.functions.getPrice().call()
19 |
20 | tx = contract.functions.safeMint(
21 | self.web3.to_checksum_address("0x739815d56A5FFc21950271199D2cf9E23B944F1c")
22 | ).build_transaction({
23 | 'value': mint_price,
24 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
25 | 'from': self.account_address,
26 | "gasPrice": self.web3.eth.gas_price
27 | })
28 | return tx
29 |
--------------------------------------------------------------------------------
/src/modules/okx_withdraw/okx_withdraw.py:
--------------------------------------------------------------------------------
1 | from typing import List, Union
2 | from asyncio import sleep
3 | import random
4 |
5 | from loguru import logger
6 | from web3 import Web3
7 | import ccxt
8 |
9 | from src.modules.okx_withdraw.utils.okx_sub_transfer import transfer_from_subaccs_to_main
10 | from src.modules.okx_withdraw.utils.data import get_withdrawal_fee
11 | from src.utils.wrappers.decorators import retry
12 | from src.utils.user.account import Account
13 |
14 | from okx_data.okx_data import (
15 | USE_PROXY,
16 | proxy,
17 | )
18 |
19 | from src.utils.data.chains import (
20 | okx_chain_mapping,
21 | chain_mapping,
22 | )
23 |
24 |
25 | class OkxWithdraw:
26 | def __init__(self, api_key: str, api_secret: str, passphrase: str, amount: Union[float, List[float]],
27 | receiver_address: str, chain: str) -> None:
28 | self.api_key = api_key
29 | self.api_secret = api_secret
30 | self.passphrase = passphrase
31 | if isinstance(amount, List):
32 | self.amount = round(random.uniform(amount[0], amount[1]), 6)
33 | elif isinstance(amount, float):
34 | self.amount = amount
35 | else:
36 | logger.error(f'amount must be List[float] or float. Got {type(amount)}')
37 | return
38 |
39 | self.receiver_address = receiver_address
40 | self.chain = chain
41 | rpc = okx_chain_mapping[chain].rpc
42 | self.web3 = Web3(Web3.HTTPProvider(rpc))
43 | self.okex = ccxt.okx({
44 | 'apiKey': self.api_key,
45 | 'secret': self.api_secret,
46 | 'password': self.passphrase,
47 | 'enableRateLimit': True,
48 | 'proxies': {
49 | 'http': proxy if USE_PROXY is True else None,
50 | 'https': proxy if USE_PROXY is True else None
51 | },
52 | })
53 |
54 | def __repr__(self) -> str:
55 | return f'Withdrawing {self.amount} ETH to {self.receiver_address} | CHAIN: {self.chain}'
56 |
57 | async def withdraw(self) -> None:
58 | try:
59 | chain_name = 'ETH' + '-' + self.chain
60 | fee = await get_withdrawal_fee('ETH', chain_name, self.okex)
61 | eth_balance_before_withdraw = self.web3.eth.get_balance(
62 | self.web3.to_checksum_address(self.receiver_address))
63 | self.okex.withdraw('ETH', self.amount, self.receiver_address, params={
64 | 'toAddress': self.receiver_address,
65 | 'chainName': chain_name,
66 | 'dest': 4,
67 | 'fee': fee,
68 | 'pwd': '-',
69 | 'amt': self.amount,
70 | 'network': self.chain
71 | })
72 |
73 | logger.success(
74 | f'Successfully withdrawn {self.amount} ETH to {self.chain} for wallet {self.receiver_address}')
75 | await self.wait_for_eth(eth_balance_before_withdraw)
76 |
77 | except Exception as ex:
78 | logger.error(f'Something went wrong {ex}')
79 | return
80 |
81 | async def wait_for_eth(self, eth_balance_before_withdraw: int) -> None:
82 | logger.info(f'Waiting for ETH to arrive on Metamask...')
83 | while True:
84 | try:
85 | balance = self.web3.eth.get_balance(
86 | self.web3.to_checksum_address(self.receiver_address))
87 | if balance > eth_balance_before_withdraw:
88 | logger.success(f'ETH has arrived | [{self.receiver_address}]')
89 | break
90 | await sleep(20)
91 | except Exception as ex:
92 | logger.error(f'Something went wrong {ex}')
93 | await sleep(10)
94 | continue
95 |
96 |
97 | class OkxDeposit(Account):
98 | def __init__(self, private_key: str, from_chain: str, amount: Union[float, List[float]],
99 | keep_value: Union[float, List[float]], withdraw_all: bool, receiver_address: str) -> None:
100 | self.from_chain = from_chain
101 | rpc = chain_mapping[from_chain.lower()].rpc
102 | super().__init__(private_key, rpc=rpc)
103 | self.scan = chain_mapping[from_chain.lower()].scan
104 | self.receiver_address = receiver_address
105 | if isinstance(amount, List):
106 | self.amount = round(random.uniform(amount[0], amount[1]), 6)
107 | elif isinstance(amount, float):
108 | self.amount = amount
109 | else:
110 | logger.error(f'amount must be List[float] or float. Got {type(amount)}')
111 | return
112 |
113 | if isinstance(keep_value, list):
114 | self.keep_value = random.uniform(keep_value[0], keep_value[1])
115 | else:
116 | self.keep_value = keep_value
117 | self.withdraw_all = withdraw_all
118 |
119 | def __repr__(self) -> str:
120 | if self.withdraw_all:
121 | balance = self.get_wallet_balance('ETH', '...')
122 | amount = (int(balance - self.keep_value * 10 ** 18)) / 10 ** 18
123 | else:
124 | amount = self.amount
125 | return f'Withdrawing {amount} ETH from {self.account_address} to {self.receiver_address} | CHAIN: {self.from_chain}'
126 |
127 | @retry()
128 | async def deposit(self) -> None:
129 | balance = self.get_wallet_balance('ETH', '...')
130 |
131 | if balance == 0:
132 | logger.error(f'Your balance is 0 | {self.account.address}')
133 | return
134 | if self.withdraw_all is True:
135 | amount = balance - int(self.keep_value * 10 ** 18)
136 | else:
137 | amount = int(self.amount * 10 ** 18)
138 |
139 | tx = {
140 | 'chainId': self.web3.eth.chain_id,
141 | 'from': self.account_address,
142 | 'to': self.web3.to_checksum_address(self.receiver_address),
143 | 'value': amount,
144 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
145 | 'gasPrice': self.web3.eth.gas_price
146 | }
147 | gas_limit = self.web3.eth.estimate_gas(tx)
148 | tx.update({'gas': gas_limit})
149 |
150 | tx_hash = self.sign_transaction(tx)
151 |
152 | self.logger.success(
153 | f'Successfully withdrawn {round((amount / 10 ** 18), 6)} from {self.account.address} to {self.receiver_address} TX: {self.scan}/{tx_hash}'
154 | )
155 | self.logger.info('Sleeping 5 minutes before SubAccount => MainAccount transfer...')
156 | await sleep(300)
157 | logger.debug('Transferring from SubAccount to MainAccount')
158 | await transfer_from_subaccs_to_main()
159 |
--------------------------------------------------------------------------------
/src/modules/okx_withdraw/utils/data.py:
--------------------------------------------------------------------------------
1 | from typing import Optional
2 |
3 | from loguru import logger
4 | import ccxt
5 |
6 |
7 | async def get_withdrawal_fee(symbol_withdraw: str, chain_name: str, exchange: ccxt.okx) -> Optional[float]:
8 | currencies = exchange.fetch_currencies()
9 | for currency in currencies:
10 | if currency == symbol_withdraw:
11 | currency_info = currencies[currency]
12 | network_info = currency_info.get('networks', None)
13 | if network_info:
14 | for network in network_info:
15 | network_data = network_info[network]
16 | network_id = network_data['id']
17 | if network_id == chain_name:
18 | withdrawal_fee = currency_info['networks'][network]['fee']
19 | if withdrawal_fee == 0:
20 | return 0
21 | else:
22 | return withdrawal_fee
23 |
24 | logger.error(f"Can't get commission value, check symbolWithdraw and network values")
25 | return
26 |
--------------------------------------------------------------------------------
/src/modules/okx_withdraw/utils/okx_sub_transfer.py:
--------------------------------------------------------------------------------
1 | from aiohttp import ClientSession
2 | from datetime import datetime
3 | from asyncio import sleep
4 | import base64
5 | import json
6 | import hmac
7 |
8 | from typing import (
9 | Callable,
10 | Awaitable,
11 | Optional,
12 | Union,
13 | Dict,
14 | )
15 |
16 | from loguru import logger
17 |
18 | from okx_data.okx_data import (
19 | SECRET_KEY,
20 | PASSPHRASE,
21 | API_KEY,
22 | )
23 |
24 |
25 | def signature(timestamp: str, method: str, url: str, body: Optional[str]
26 | ) -> Union[str, Callable[[str, str, str, Optional[str]], Awaitable[str]]]:
27 | try:
28 | if not body:
29 | body = ""
30 | message = timestamp + method.upper() + url + body
31 | mac = hmac.new(
32 | bytes(SECRET_KEY, encoding="utf-8"),
33 | bytes(message, encoding="utf-8"),
34 | digestmod="sha256",
35 | )
36 | d = mac.digest()
37 | return base64.b64encode(d).decode("utf-8")
38 | except Exception as ex:
39 | logger.error(ex)
40 | return signature(timestamp, method, url, body)
41 |
42 |
43 | def generate_request_headers(url: str, method: str, body=''
44 | ) -> Dict[str, Union[str, Callable[[str, str, str, Optional[str]], str]]]:
45 | dt_now = datetime.utcnow()
46 | ms = str(dt_now.microsecond).zfill(6)[:3]
47 | timestamp = f"{dt_now:%Y-%m-%dT%H:%M:%S}.{ms}Z"
48 | headers = {
49 | "Content-Type": "application/json",
50 | "OK-ACCESS-KEY": API_KEY,
51 | "OK-ACCESS-SIGN": signature(timestamp, method, url, body),
52 | "OK-ACCESS-TIMESTAMP": timestamp,
53 | "OK-ACCESS-PASSPHRASE": PASSPHRASE,
54 | 'x-simulated-trading': '0'
55 | }
56 | return headers
57 |
58 |
59 | async def send_request(url: str, timeout: int, headers: dict, method: str, data='') -> Optional[str]:
60 | try:
61 | async with ClientSession(headers=headers) as session:
62 | async with session.get(url, timeout=timeout, data=data) if method == 'GET' \
63 | else session.post(url, timeout=timeout, data=data) as response:
64 | if response.status == 200:
65 | await sleep(2)
66 | return json.loads(await response.text())
67 | logger.error(f"Couldn't send request {url} : {await response.text()}")
68 | return False
69 | except Exception as ex:
70 | logger.error(ex)
71 | return False
72 |
73 |
74 | async def transfer_from_subaccs_to_main(token='ETH') -> None:
75 | try:
76 | headers = generate_request_headers(url='/api/v5/users/subaccount/list',
77 | method='GET')
78 | list_sub = await send_request(f"https://www.okx.com/api/v5/users/subaccount/list", 10, headers, 'GET')
79 | if not list_sub:
80 | logger.info(f"You don't have Sub Accounts!")
81 | return
82 | for sub_data in list_sub['data']:
83 | name = sub_data['subAcct']
84 |
85 | headers = generate_request_headers(
86 | url=f"/api/v5/asset/subaccount/balances?subAcct={name}&ccy={token}",
87 | method='GET')
88 | sub_balance = await send_request(
89 | f"https://www.okx.com/api/v5/asset/subaccount/balances?subAcct={name}&ccy={token}", 10, headers,
90 | 'GET')
91 | if not sub_balance:
92 | await sleep(10)
93 | continue
94 | sub_balance = float(sub_balance['data'][0]['bal'])
95 | if sub_balance == 0:
96 | logger.info(f'Sub Account: {name} | Balance: 0')
97 | await sleep(10)
98 | continue
99 |
100 | body = {"ccy": f"{token}", "amt": str(sub_balance), "from": 6, "to": 6, "type": "2",
101 | "subAcct": name}
102 |
103 | headers = generate_request_headers(url=f"/api/v5/asset/transfer",
104 | body=str(body), method='POST')
105 | res = await send_request("https://www.okx.com/api/v5/asset/transfer", 10, headers, 'POST', str(body))
106 | if len(res['data']) != 0:
107 | logger.success(f'Successfully transferred from {name} => MAIN: {sub_balance} {token}')
108 | await sleep(30)
109 | else:
110 | if 'Insufficient balance' in str(res):
111 | await sleep(2)
112 | continue
113 | logger.warning(f'Error - {res}')
114 | await sleep(1)
115 |
116 | except Exception as ex:
117 | logger.error(ex)
118 | await sleep(2)
119 | return
120 |
--------------------------------------------------------------------------------
/src/modules/other/multi_approve/multi_approve.py:
--------------------------------------------------------------------------------
1 | from asyncio import sleep
2 | import random
3 |
4 | from src.utils.wrappers.decorators import retry
5 | from src.utils.data.contracts import contracts
6 | from src.utils.user.account import Account
7 | from src.utils.data.tokens import tokens
8 |
9 | from config import (
10 | MIN_PAUSE,
11 | MAX_PAUSE,
12 | )
13 |
14 |
15 | class MultiApprove(Account):
16 | def __init__(self, private_key: str) -> None:
17 | self.private_key = private_key
18 | super().__init__(private_key=private_key)
19 |
20 | def __str__(self) -> str:
21 | return f'MultiApprove | [{self.account_address}]'
22 |
23 | @retry()
24 | async def approve(self) -> None:
25 | contract_list = [
26 | contracts['skydrome'],
27 | contracts['punkswap'],
28 | contracts['spacefi'],
29 | contracts['zebra'],
30 | contracts['syncswap']
31 | ]
32 | token_list = list(tokens)
33 | random.shuffle(token_list)
34 |
35 | for token in token_list:
36 | contract_address = random.choice(contract_list)
37 | if token in ["ETH", "WETH"]:
38 | continue
39 | self.logger.info(f'Approving {token}...')
40 | tx_hash = await self.approve_token(0, self.private_key, tokens[token],
41 | contract_address, self.account_address, self.web3)
42 | self.logger.info(f'Approve TX: https://scrollscan.com/tx/{tx_hash}')
43 | random_sleep = random.randint(MIN_PAUSE, MAX_PAUSE)
44 | self.logger.info(f'Sleeping {random_sleep} seconds...')
45 | await sleep(random_sleep)
46 |
--------------------------------------------------------------------------------
/src/modules/other/rubyscore/rubyscore.py:
--------------------------------------------------------------------------------
1 | from src.utils.wrappers.decorators import retry
2 | from src.utils.user.account import Account
3 |
4 | from src.utils.data.contracts import (
5 | contracts,
6 | abi_names,
7 | )
8 |
9 |
10 | class RubyScore(Account):
11 | def __init__(self, private_key: str) -> None:
12 | super().__init__(private_key)
13 |
14 | def __str__(self) -> str:
15 | return f'[{self.account_address}] Voting on RubyScore'
16 |
17 | @retry()
18 | async def vote(self) -> None:
19 | contract = self.load_contract(contracts['rubyscore'], self.web3, abi_names['rubyscore'])
20 | tx = contract.functions.vote().build_transaction({
21 | 'value': 0,
22 | 'nonce': self.web3.eth.get_transaction_count(self.account_address),
23 | 'from': self.account_address,
24 | "gasPrice": self.web3.eth.gas_price
25 | })
26 |
27 | tx_hash = self.sign_transaction(tx)
28 | self.wait_until_tx_finished(tx_hash)
29 |
--------------------------------------------------------------------------------
/src/modules/swaps/punk_swap/punk_swap.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | # from src.utils.base_liquidity_remove import BaseLiquidityRemove
8 | from src.utils.base_liquidity_remove import BaseLiquidityRemove
9 | from src.utils.base_liquidity import BaseLiquidity
10 | from src.utils.base_swap import BaseSwap
11 | from src.utils.data.types import Types
12 |
13 | from src.utils.data.contracts import (
14 | contracts,
15 | abi_names,
16 | )
17 |
18 | from src.modules.swaps.punk_swap.utils.transaction_data import (
19 | create_liquidity_remove_tx,
20 | create_liquidity_tx,
21 | get_amount_out,
22 | create_swap_tx,
23 | )
24 |
25 |
26 | class PunkSwap(BaseSwap):
27 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]],
28 | amount: Union[float, List[float]], use_percentage: bool, swap_percentage: Union[float, List[float]],
29 | swap_all_balance: bool) -> None:
30 | contract_address = contracts['punkswap']
31 | abi_name = abi_names['punkswap']
32 | dex_name = self.__class__.__name__
33 |
34 | super().__init__(private_key, from_token, to_token, amount, use_percentage, swap_percentage, swap_all_balance,
35 | contract_address, abi_name, dex_name)
36 |
37 | def __repr__(self) -> str:
38 | return f'{self.__class__.__name__}: {self.account_address} | {self.from_token} => {self.to_token}'
39 |
40 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
41 | to_token_address: Address) -> Types.AmountOut:
42 | return get_amount_out(contract, amount, from_token_address, to_token_address)
43 |
44 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
45 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
46 | web3: Web3) -> Types.SwapTransaction:
47 | return create_swap_tx(from_token, to_token, contract, amount_out, from_token_address, to_token_address,
48 | account_address, amount, web3)
49 |
50 |
51 | class PunkSwapLiquidity(BaseLiquidity):
52 | def __init__(self, private_key: str, token: str, token2: str, amount: Union[float, List[float]],
53 | use_percentage: bool, liquidity_percentage: Union[float, List[float]]) -> None:
54 | contract_address = contracts['punkswap']
55 | abi_name = abi_names['punkswap']
56 | dex_name = self.__class__.__name__
57 | super().__init__(private_key, token, token2, amount, use_percentage, liquidity_percentage,
58 | contract_address, abi_name, dex_name)
59 |
60 | def __repr__(self) -> str:
61 | return f'{self.__class__.__name__}: {self.account_address}'
62 |
63 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
64 | to_token_address: Address) -> Types.AmountOut:
65 | return get_amount_out(contract, amount, from_token_address, to_token_address)
66 |
67 | def create_liquidity_tx(self, from_token: str, contract: Contract, amount_out: int, from_token_address: str,
68 | to_token_address: str, account_address: Address, amount: int, web3: Web3
69 | ) -> Types.LiquidityTransaction:
70 | return create_liquidity_tx(from_token, contract, amount_out, to_token_address,
71 | account_address, amount, web3)
72 |
73 | async def get_swap_instance(self, private_key: str, token: str, token2: str, amount: int) -> PunkSwap:
74 | return PunkSwap(private_key, token, token2, amount, False, 0, False)
75 |
76 |
77 | class PunkSwapLiquidityRemove(BaseLiquidityRemove):
78 | def __init__(self, private_key: str, from_token_pair: Union[str, List[str]], remove_all: bool,
79 | removing_percentage: float, token: str = None) -> None:
80 | contract_address = contracts['punkswap']
81 | abi_name = abi_names['punkswap']
82 | pool_name = 'PunkSwap'
83 | super().__init__(private_key, from_token_pair, remove_all, removing_percentage, contract_address, abi_name,
84 | pool_name, token=token)
85 |
86 | def __repr__(self) -> str:
87 | return f'{self.__class__.__name__}: {self.account_address}'
88 |
89 | def create_liquidity_remove_tx(self, web3: Web3, contract: Contract, from_token_pair_address: str,
90 | amount: int, account_address: Address, token=None
91 | ) -> Types.LiquidityRemoveTransaction:
92 | return create_liquidity_remove_tx(web3, contract, from_token_pair_address, amount, account_address, token)
93 |
--------------------------------------------------------------------------------
/src/modules/swaps/punk_swap/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from time import time
2 |
3 | from web3.contract import Contract
4 | from web3.types import TxParams
5 | from eth_typing import Address
6 |
7 | from config import SLIPPAGE
8 | from web3 import Web3
9 |
10 | from src.utils.data.tokens import tokens
11 |
12 |
13 | def get_amount_out(contract: Contract, amount: int, from_token_address: Address,
14 | to_token_address: Address) -> int:
15 | amount_out = contract.functions.getAmountsOut(
16 | amount,
17 | [from_token_address, to_token_address]
18 | ).call()
19 | return amount_out[1]
20 |
21 |
22 | def create_swap_tx(from_token: str, to_token: str, contract: Contract, amount_out: int, from_token_address: str,
23 | to_token_address: str, account_address: Address, amount: int, web3: Web3) -> TxParams:
24 | if from_token.lower() == 'eth':
25 | tx = contract.functions.swapExactETHForTokens(
26 | int(amount_out * (1 - SLIPPAGE)),
27 | [Web3.to_checksum_address(from_token_address), Web3.to_checksum_address(tokens['PUNK']),
28 | Web3.to_checksum_address(to_token_address)] if not to_token.upper() == 'PUNK' else
29 | [Web3.to_checksum_address(from_token_address), Web3.to_checksum_address(to_token_address)],
30 | account_address,
31 | int(time() + 1200)
32 | ).build_transaction({
33 | 'value': amount if from_token.lower() == 'eth' else 0,
34 | 'nonce': web3.eth.get_transaction_count(account_address),
35 | 'from': account_address,
36 | 'gasPrice': web3.eth.gas_price,
37 | })
38 | elif to_token.lower() == 'eth':
39 | tx = contract.functions.swapExactTokensForETH(
40 | amount,
41 | int(amount_out * (1 - SLIPPAGE)),
42 | [Web3.to_checksum_address(from_token_address), Web3.to_checksum_address(tokens['PUNK']),
43 | Web3.to_checksum_address(to_token_address)] if not from_token.upper() == 'PUNK' else
44 | [Web3.to_checksum_address(from_token_address), Web3.to_checksum_address(to_token_address)],
45 | account_address,
46 | int(time() + 1200)
47 | ).build_transaction({
48 | 'value': 0,
49 | 'nonce': web3.eth.get_transaction_count(account_address),
50 | 'from': account_address,
51 | 'gasPrice': web3.eth.gas_price,
52 | })
53 | else:
54 | tx = contract.functions.swapExactTokensForTokens(
55 | amount,
56 | int(amount_out * (1 - SLIPPAGE)),
57 | [from_token_address, to_token_address],
58 | account_address,
59 | int(time() + 1200)
60 | ).build_transaction({
61 | 'value': amount if from_token.lower() == 'eth' else 0,
62 | 'nonce': web3.eth.get_transaction_count(account_address),
63 | 'from': account_address,
64 | 'gasPrice': web3.eth.gas_price,
65 | })
66 |
67 | return tx
68 |
69 |
70 | def create_liquidity_tx(from_token: str, contract: Contract, amount_out: int, to_token_address: str,
71 | account_address: Address, amount: int, web3: Web3) -> TxParams:
72 | if from_token.lower() == 'eth':
73 | tx = contract.functions.addLiquidityETH(
74 | to_token_address,
75 | amount_out,
76 | int(amount_out * (1 - SLIPPAGE)),
77 | int(amount * (1 - SLIPPAGE)),
78 | account_address,
79 | int(time() + 1200)
80 | ).build_transaction({
81 | 'value': amount if from_token.lower() == 'eth' else 0,
82 | 'nonce': web3.eth.get_transaction_count(account_address),
83 | 'from': account_address,
84 | "gasPrice": web3.eth.gas_price
85 | })
86 | else:
87 | from_token_address = tokens[from_token]
88 | tx = contract.functions.addLiquidity(
89 | from_token_address,
90 | to_token_address,
91 | amount,
92 | amount_out,
93 | int(amount * (1 - SLIPPAGE)),
94 | int(amount_out * (1 - SLIPPAGE)),
95 | account_address,
96 | int(time() + 1200)
97 | ).build_transaction({
98 | 'value': amount if from_token.lower() == 'eth' else 0,
99 | 'nonce': web3.eth.get_transaction_count(account_address),
100 | 'from': account_address,
101 | 'gasPrice': web3.eth.gas_price,
102 | })
103 |
104 | return tx
105 |
106 |
107 | def create_liquidity_remove_tx(web3: Web3, contract: Contract, from_token_pair_address: str, amount: int,
108 | account_address: Address, token: str) -> TxParams:
109 | if token.lower() == 'eth':
110 | tx = contract.functions.removeLiquidityETH(
111 | from_token_pair_address,
112 | amount,
113 | 0,
114 | 0,
115 | account_address,
116 | int(time() + 1200)
117 | ).build_transaction({
118 | 'value': 0,
119 | 'nonce': web3.eth.get_transaction_count(account_address),
120 | 'from': account_address,
121 | 'gasPrice': web3.eth.gas_price,
122 | })
123 | else:
124 | from_token_address = tokens[token]
125 | tx = contract.functions.removeLiquidity(
126 | from_token_address,
127 | from_token_pair_address,
128 | amount,
129 | 0,
130 | 0,
131 | account_address,
132 | int(time() + 1200)
133 | ).build_transaction({
134 | 'value': 0,
135 | 'nonce': web3.eth.get_transaction_count(account_address),
136 | 'from': account_address,
137 | 'gasPrice': web3.eth.gas_price,
138 | })
139 |
140 | return tx
141 |
--------------------------------------------------------------------------------
/src/modules/swaps/skydrome/skydrome_swap.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | from src.utils.base_liquidity_remove import BaseLiquidityRemove
8 | from src.utils.base_liquidity import BaseLiquidity
9 | from src.utils.base_swap import BaseSwap
10 | from src.utils.data.types import Types
11 |
12 | from src.utils.data.contracts import (
13 | contracts,
14 | abi_names,
15 | )
16 |
17 | from src.modules.swaps.skydrome.utils.transaction_data import (
18 | create_liquidity_remove_tx,
19 | create_liquidity_tx,
20 | get_amount_out,
21 | create_swap_tx,
22 | )
23 |
24 |
25 | class SkyDromeSwap(BaseSwap):
26 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]],
27 | amount: Union[float, List[float]], use_percentage: bool, swap_percentage: Union[float, List[float]],
28 | swap_all_balance: bool) -> None:
29 | contract_address = contracts['skydrome']
30 | abi_name = abi_names['skydrome']
31 | dex_name = self.__class__.__name__
32 |
33 | super().__init__(private_key, from_token, to_token, amount, use_percentage, swap_percentage, swap_all_balance,
34 | contract_address, abi_name, dex_name)
35 |
36 | def __repr__(self) -> str:
37 | return f'{self.__class__.__name__}: {self.account_address} | {self.from_token} => {self.to_token}'
38 |
39 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
40 | to_token_address: Address) -> Types.AmountOut:
41 | return get_amount_out(contract, amount, from_token_address, to_token_address)
42 |
43 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
44 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
45 | web3: Web3) -> Types.SwapTransaction:
46 | return create_swap_tx(from_token, to_token, contract, from_token_address, to_token_address,
47 | account_address, amount, web3)
48 |
49 |
50 | class SkyDromeLiquidity(BaseLiquidity):
51 | def __init__(self, private_key: str, token: str, token2: str, amount: Union[float, List[float]],
52 | use_percentage: bool, liquidity_percentage: Union[float, List[float]]) -> None:
53 | contract_address = contracts['skydrome']
54 | abi_name = abi_names['skydrome']
55 | dex_name = self.__class__.__name__
56 | super().__init__(private_key, token, token2, amount, use_percentage, liquidity_percentage,
57 | contract_address, abi_name, dex_name)
58 |
59 | def __repr__(self) -> str:
60 | return f'{self.__class__.__name__}: {self.account_address}'
61 |
62 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
63 | to_token_address: Address) -> Types.AmountOut:
64 | return get_amount_out(contract, amount, from_token_address, to_token_address)
65 |
66 | def create_liquidity_tx(self, from_token: str, contract: Contract, amount_out: int, from_token_address: str,
67 | to_token_address: str, account_address: Address, amount: int, web3: Web3
68 | ) -> Types.LiquidityTransaction:
69 | return create_liquidity_tx(from_token, contract, amount_out, to_token_address,
70 | account_address, amount, web3)
71 |
72 | async def get_swap_instance(self, private_key: str, token: str, token2: str, amount: int) -> SkyDromeSwap:
73 | return SkyDromeSwap(private_key, token, token2, amount, False, 0, False)
74 |
75 |
76 | class SkyDromeLiquidityRemove(BaseLiquidityRemove):
77 | def __init__(self, private_key: str, from_token_pair: Union[str, List[str]], remove_all: bool,
78 | removing_percentage: float, token: str = None) -> None:
79 | contract_address = contracts['skydrome']
80 | abi_name = abi_names['skydrome']
81 | pool_name = 'SkyDrome'
82 | super().__init__(private_key, from_token_pair, remove_all, removing_percentage, contract_address, abi_name,
83 | pool_name, token=token)
84 |
85 | def __repr__(self) -> str:
86 | return f'{self.__class__.__name__}: {self.account_address}'
87 |
88 | def create_liquidity_remove_tx(self, web3: Web3, contract: Contract, from_token_pair_address: str,
89 | amount: int, account_address: Address, token: str = None
90 | ) -> Types.LiquidityRemoveTransaction:
91 | return create_liquidity_remove_tx(web3, contract, from_token_pair_address, amount, account_address, token)
92 |
--------------------------------------------------------------------------------
/src/modules/swaps/skydrome/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from time import time
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3.types import TxParams
6 | from web3 import Web3
7 |
8 | from src.utils.data.tokens import tokens
9 | from config import SLIPPAGE
10 |
11 |
12 | def get_amounts_out(contract: Contract, amount: int, from_token_address: Address,
13 | to_token_address: Address) -> tuple[int, bool]:
14 | amount_out, swap_type = contract.functions.getAmountOut(
15 | amount,
16 | from_token_address,
17 | to_token_address
18 | ).call()
19 | return amount_out, swap_type
20 |
21 |
22 | def get_amount_out(contract: Contract, amount: int, from_token_address: Address,
23 | to_token_address: Address) -> int:
24 | swap_type = get_amounts_out(contract, amount, from_token_address, to_token_address)[1]
25 | amount_out = contract.functions.getAmountsOut(
26 | amount,
27 | [[from_token_address, to_token_address, swap_type]]
28 | ).call()
29 | return amount_out[1]
30 |
31 |
32 | def create_swap_tx(from_token: str, to_token: str, contract: Contract, from_token_address: str,
33 | to_token_address: str, account_address: Address, amount: int, web3: Web3) -> TxParams:
34 | amount_out, swap_type = get_amounts_out(contract, amount, web3.to_checksum_address(from_token_address),
35 | web3.to_checksum_address(to_token_address))
36 | if from_token.lower() == 'eth':
37 | tx = contract.functions.swapExactETHForTokens(
38 | int(amount_out * (1 - SLIPPAGE)),
39 | [
40 | [
41 | web3.to_checksum_address(from_token_address),
42 | web3.to_checksum_address(to_token_address),
43 | swap_type
44 | ]
45 | ],
46 | account_address,
47 | int(time() + 1200)
48 | ).build_transaction({
49 | 'value': amount if from_token.lower() == 'eth' else 0,
50 | 'nonce': web3.eth.get_transaction_count(account_address),
51 | 'from': account_address,
52 | 'gasPrice': web3.eth.gas_price,
53 | })
54 | elif to_token.lower() == 'eth':
55 | tx = contract.functions.swapExactTokensForETH(
56 | amount,
57 | int(amount_out * (1 - SLIPPAGE)),
58 | [
59 | [
60 | web3.to_checksum_address(from_token_address),
61 | web3.to_checksum_address(to_token_address),
62 | swap_type
63 | ]
64 | ],
65 | account_address,
66 | int(time() + 1200)
67 | ).build_transaction({
68 | 'value': amount if from_token.lower() == 'eth' else 0,
69 | 'nonce': web3.eth.get_transaction_count(account_address),
70 | 'from': account_address,
71 | 'gasPrice': web3.eth.gas_price,
72 | })
73 | else:
74 | tx = contract.functions.swapExactTokensForTokens(
75 | amount,
76 | int(amount_out * (1 - SLIPPAGE)),
77 | [
78 | [
79 | web3.to_checksum_address(from_token_address),
80 | web3.to_checksum_address(to_token_address),
81 | swap_type
82 | ]
83 | ],
84 | account_address,
85 | int(time() + 1200)
86 | ).build_transaction({
87 | 'value': amount if from_token.lower() == 'eth' else 0,
88 | 'nonce': web3.eth.get_transaction_count(account_address),
89 | 'from': account_address,
90 | 'gasPrice': web3.eth.gas_price,
91 | })
92 |
93 | return tx
94 |
95 |
96 | def create_liquidity_tx(from_token: str, contract: Contract, amount_out: int, to_token_address: str,
97 | account_address: Address, amount: int, web3: Web3) -> TxParams:
98 | from_token_address = tokens[from_token]
99 | return contract.functions.addLiquidity(
100 | from_token_address,
101 | to_token_address,
102 | True,
103 | amount,
104 | amount_out,
105 | int(amount * (1 - SLIPPAGE)),
106 | int(amount_out * (1 - SLIPPAGE)),
107 | account_address,
108 | int(time() + 1200)
109 | ).build_transaction({
110 | 'value': amount if from_token.lower() == 'eth' else 0,
111 | 'nonce': web3.eth.get_transaction_count(account_address),
112 | 'from': account_address,
113 | 'gasPrice': web3.eth.gas_price,
114 | })
115 |
116 |
117 | def create_liquidity_remove_tx(web3: Web3, contract: Contract, from_token_pair_address: str, amount: int,
118 | account_address: Address, token: str) -> TxParams:
119 | from_token_address = tokens[token]
120 | tx = contract.functions.removeLiquidity(
121 | from_token_address,
122 | from_token_pair_address,
123 | True,
124 | amount,
125 | 1,
126 | 1,
127 | account_address,
128 | int(time() + 1200)
129 | ).build_transaction({
130 | 'value': 0,
131 | 'nonce': web3.eth.get_transaction_count(account_address),
132 | 'from': account_address,
133 | 'gasPrice': web3.eth.gas_price,
134 | })
135 | return tx
136 |
--------------------------------------------------------------------------------
/src/modules/swaps/spacefi/spacefi_swap.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | from src.utils.base_liquidity_remove import BaseLiquidityRemove
8 | from src.utils.base_liquidity import BaseLiquidity
9 | from src.utils.base_swap import BaseSwap
10 | from src.utils.data.types import Types
11 |
12 | from src.utils.data.contracts import (
13 | contracts,
14 | abi_names,
15 | )
16 |
17 | from src.modules.swaps.spacefi.utils.transaction_data import (
18 | create_liquidity_remove_tx,
19 | create_liquidity_tx,
20 | get_amount_out,
21 | create_swap_tx,
22 | )
23 |
24 |
25 | class SpaceFiSwap(BaseSwap):
26 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]],
27 | amount: Union[float, List[float]], use_percentage: bool, swap_percentage: Union[float, List[float]],
28 | swap_all_balance: bool) -> None:
29 | contract_address = contracts['spacefi']
30 | abi_name = abi_names['spacefi']
31 | dex_name = self.__class__.__name__
32 |
33 | super().__init__(private_key, from_token, to_token, amount, use_percentage, swap_percentage, swap_all_balance,
34 | contract_address, abi_name, dex_name)
35 |
36 | def __repr__(self) -> str:
37 | return f'{self.__class__.__name__}: {self.account_address} | {self.from_token} => {self.to_token}'
38 |
39 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
40 | to_token_address: Address) -> Types.AmountOut:
41 | return get_amount_out(contract, amount, from_token_address, to_token_address)
42 |
43 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
44 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
45 | web3: Web3) -> Types.SwapTransaction:
46 | return create_swap_tx(from_token, contract, amount_out, from_token_address, to_token_address,
47 | account_address, amount, web3)
48 |
49 |
50 | class SpaceFiLiquidity(BaseLiquidity):
51 | def __init__(self, private_key: str, token: str, token2: str, amount: Union[float, List[float]],
52 | use_percentage: bool, liquidity_percentage: Union[float, List[float]]) -> None:
53 | contract_address = contracts['spacefi']
54 | abi_name = abi_names['spacefi']
55 | dex_name = self.__class__.__name__
56 | super().__init__(private_key, token, token2, amount, use_percentage, liquidity_percentage,
57 | contract_address, abi_name, dex_name)
58 |
59 | def __repr__(self) -> str:
60 | return f'{self.__class__.__name__}: {self.account_address}'
61 |
62 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
63 | to_token_address: Address) -> Types.AmountOut:
64 | return get_amount_out(contract, amount, from_token_address, to_token_address)
65 |
66 | def create_liquidity_tx(self, from_token: str, contract: Contract, amount_out: int, from_token_address: str,
67 | to_token_address: str, account_address: Address, amount: int, web3: Web3
68 | ) -> Types.LiquidityTransaction:
69 | return create_liquidity_tx(from_token, contract, amount_out, to_token_address,
70 | account_address, amount, web3)
71 |
72 | async def get_swap_instance(self, private_key: str, token: str, token2: str, amount: int) -> SpaceFiSwap:
73 | return SpaceFiSwap(private_key, token, token2, amount, False, 0, False)
74 |
75 |
76 | class SpaceFiLiquidityRemove(BaseLiquidityRemove):
77 | def __init__(self, private_key: str, from_token_pair: Union[str, List[str]], remove_all: bool,
78 | removing_percentage: float, token: str) -> None:
79 | contract_address = contracts['spacefi']
80 | abi_name = abi_names['spacefi']
81 | pool_name = 'SpaceFi'
82 | super().__init__(private_key, from_token_pair, remove_all, removing_percentage, contract_address, abi_name,
83 | pool_name, token=token)
84 |
85 | def __repr__(self) -> str:
86 | return f'{self.__class__.__name__}: {self.account_address}'
87 |
88 | def create_liquidity_remove_tx(self, web3: Web3, contract: Contract, from_token_pair_address: str,
89 | amount: int, account_address: Address, token=None
90 | ) -> Types.LiquidityRemoveTransaction:
91 | return create_liquidity_remove_tx(web3, contract, from_token_pair_address, amount, account_address, token)
92 |
--------------------------------------------------------------------------------
/src/modules/swaps/spacefi/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from time import time
2 |
3 | from web3.contract import Contract
4 | from web3.types import TxParams
5 | from eth_typing import Address
6 |
7 | from config import SLIPPAGE
8 | from web3 import Web3
9 |
10 | from src.utils.data.tokens import tokens
11 |
12 |
13 | def get_amount_out(contract: Contract, amount: int, from_token_address: Address,
14 | to_token_address: Address) -> int:
15 | amount_out = contract.functions.getAmountsOut(
16 | amount,
17 | [from_token_address, to_token_address]
18 | ).call()
19 | return amount_out[1]
20 |
21 |
22 | def create_swap_tx(from_token: str, contract: Contract, amount_out: int, from_token_address: str,
23 | to_token_address: str, account_address: Address, amount: int, web3: Web3) -> TxParams:
24 | if from_token.lower() == 'eth':
25 | tx = contract.functions.swapExactETHForTokens(
26 | int(amount_out * (1 - SLIPPAGE)),
27 | [web3.to_checksum_address(from_token_address), web3.to_checksum_address(to_token_address)],
28 | account_address,
29 | int(time() + 1200)
30 | ).build_transaction({
31 | 'value': amount if from_token.lower() == 'eth' else 0,
32 | 'nonce': web3.eth.get_transaction_count(account_address),
33 | 'from': account_address,
34 | 'gasPrice': web3.eth.gas_price,
35 | })
36 | else:
37 | tx = contract.functions.swapExactTokensForTokens(
38 | amount,
39 | int(amount_out * (1 - SLIPPAGE)),
40 | [web3.to_checksum_address(from_token_address), web3.to_checksum_address(to_token_address)],
41 | account_address,
42 | int(time() + 1200)
43 | ).build_transaction({
44 | 'value': amount if from_token.lower() == 'eth' else 0,
45 | 'nonce': web3.eth.get_transaction_count(account_address),
46 | 'from': account_address,
47 | 'gasPrice': web3.eth.gas_price,
48 | })
49 |
50 | return tx
51 |
52 |
53 | def create_liquidity_tx(from_token: str, contract: Contract, amount_out: int, to_token_address: str,
54 | account_address: Address, amount: int, web3: Web3) -> TxParams:
55 | if from_token.lower() == 'eth':
56 | tx = contract.functions.addLiquidityETH(
57 | web3.to_checksum_address(to_token_address),
58 | amount_out,
59 | int(amount_out * (1 - SLIPPAGE)),
60 | int(amount * (1 - SLIPPAGE)),
61 | account_address,
62 | int(time() + 1200)
63 | ).build_transaction({
64 | 'value': amount if from_token.lower() == 'eth' else 0,
65 | 'nonce': web3.eth.get_transaction_count(account_address),
66 | 'from': account_address,
67 | 'gasPrice': web3.eth.gas_price,
68 | })
69 | else:
70 | from_token_address = tokens[from_token]
71 | tx = contract.functions.addLiquidity(
72 | web3.to_checksum_address(from_token_address),
73 | to_token_address,
74 | amount,
75 | amount_out,
76 | int(amount * (1 - SLIPPAGE)),
77 | int(amount_out * (1 - SLIPPAGE)),
78 | account_address,
79 | int(time() + 1200)
80 | ).build_transaction({
81 | 'value': amount if from_token.lower() == 'eth' else 0,
82 | 'nonce': web3.eth.get_transaction_count(account_address),
83 | 'from': account_address,
84 | 'gasPrice': web3.eth.gas_price,
85 | })
86 |
87 | return tx
88 |
89 |
90 | def create_liquidity_remove_tx(web3: Web3, contract: Contract, from_token_pair_address: str, amount: int,
91 | account_address: Address, token: str) -> TxParams:
92 | if token.lower() == 'eth':
93 | tx = contract.functions.removeLiquidityETH(
94 | web3.to_checksum_address(from_token_pair_address),
95 | amount,
96 | 0,
97 | 0,
98 | account_address,
99 | int(time() + 1200)
100 | ).build_transaction({
101 | 'value': 0,
102 | 'nonce': web3.eth.get_transaction_count(account_address),
103 | 'from': account_address,
104 | 'gasPrice': web3.eth.gas_price,
105 | })
106 | else:
107 | from_token_address = tokens[token]
108 | tx = contract.functions.removeLiquidity(
109 | web3.to_checksum_address(from_token_address),
110 | web3.to_checksum_address(from_token_pair_address),
111 | amount,
112 | 0,
113 | 0,
114 | account_address,
115 | int(time() + 1200)
116 | ).build_transaction({
117 | 'value': 0,
118 | 'nonce': web3.eth.get_transaction_count(account_address),
119 | 'from': account_address,
120 | 'gasPrice': web3.eth.gas_price,
121 | })
122 |
123 | return tx
124 |
--------------------------------------------------------------------------------
/src/modules/swaps/sync_swap/sync_swap.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | from src.utils.base_liquidity_remove import BaseLiquidityRemove
8 | from src.utils.base_liquidity import BaseLiquidity
9 | from src.utils.base_swap import BaseSwap
10 | from src.utils.data.types import Types
11 |
12 | from src.utils.data.contracts import (
13 | contracts,
14 | abi_names,
15 | )
16 |
17 | from src.modules.swaps.sync_swap.utils.transaction_data import (
18 | create_liquidity_remove_tx,
19 | create_liquidity_tx,
20 | get_amount_out,
21 | create_swap_tx,
22 | )
23 |
24 |
25 | class SyncSwapSwap(BaseSwap):
26 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]],
27 | amount: Union[float, List[float]], use_percentage: bool, swap_percentage: Union[float, List[float]],
28 | swap_all_balance: bool) -> None:
29 | contract_address = contracts['syncswap']
30 | abi_name = abi_names['syncswap']
31 | dex_name = self.__class__.__name__
32 |
33 | super().__init__(private_key, from_token, to_token, amount, use_percentage, swap_percentage, swap_all_balance,
34 | contract_address, abi_name, dex_name)
35 |
36 | def __repr__(self) -> str:
37 | return f'{self.__class__.__name__}: {self.account_address} | {self.from_token} => {self.to_token}'
38 |
39 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
40 | to_token_address: Address) -> Types.AmountOut:
41 | return get_amount_out(amount, from_token_address, to_token_address, self.web3, self.account_address)
42 |
43 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
44 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
45 | web3: Web3) -> Types.SwapTransaction:
46 | return create_swap_tx(from_token, contract, amount_out, from_token_address, to_token_address,
47 | account_address, amount, web3)
48 |
49 |
50 | class SyncSwapLiquidity(BaseLiquidity):
51 | def __init__(self, private_key: str, token: str, token2: str, amount: Union[float, List[float]],
52 | use_percentage: bool, liquidity_percentage: Union[float, List[float]]) -> None:
53 | contract_address = contracts['syncswap']
54 | abi_name = abi_names['syncswap']
55 | dex_name = self.__class__.__name__
56 | super().__init__(private_key, token, token2, amount, use_percentage, liquidity_percentage,
57 | contract_address, abi_name, dex_name)
58 |
59 | def __repr__(self) -> str:
60 | return f'{self.__class__.__name__}: {self.account_address}'
61 |
62 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
63 | to_token_address: Address) -> Types.AmountOut:
64 | return get_amount_out(contract, amount, from_token_address, to_token_address, self.account_address)
65 |
66 | def create_liquidity_tx(self, from_token: str, contract: Contract, amount_out: int, from_token_address: str,
67 | to_token_address: str, account_address: Address, amount: int, web3: Web3
68 | ) -> Types.LiquidityTransaction:
69 | return create_liquidity_tx(from_token, contract, to_token_address, account_address, amount,
70 | web3, from_token_address)
71 |
72 | async def get_swap_instance(self, private_key: str, token: str, token2: str, amount: int) -> SyncSwapSwap:
73 | return SyncSwapSwap(private_key, token, token2, amount, False, 0, False)
74 |
75 |
76 | class SyncSwapLiquidityRemove(BaseLiquidityRemove):
77 | def __init__(self, private_key: str, from_token_pair: Union[str, List[str]], remove_all: bool,
78 | removing_percentage: float, token: str = None) -> None:
79 | contract_address = contracts['syncswap']
80 | abi_name = abi_names['syncswap']
81 | pool_name = 'SyncSwap'
82 |
83 | super().__init__(private_key, from_token_pair, remove_all, removing_percentage, contract_address, abi_name,
84 | pool_name, token=token)
85 |
86 | def __repr__(self) -> str:
87 | return f'{self.__class__.__name__}: {self.account_address}'
88 |
89 | def create_liquidity_remove_tx(self, web3: Web3, contract: Contract, from_token_pair_address: str,
90 | amount: int, account_address: Address, token: str = None
91 | ) -> Types.LiquidityRemoveTransaction:
92 | return create_liquidity_remove_tx(web3, contract, from_token_pair_address, amount, account_address, token)
93 |
--------------------------------------------------------------------------------
/src/modules/swaps/sync_swap/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from web3.middleware import geth_poa_middleware
2 | from web3.contract import Contract
3 | from web3.types import TxParams
4 | from eth_typing import Address
5 | from eth_abi import encode
6 | from loguru import logger
7 | from web3 import Web3
8 |
9 | from src.utils.data.tokens import tokens
10 | from src.utils.user.utils import Utils
11 | from config import SLIPPAGE
12 |
13 |
14 | def get_amount_out(amount: int, from_token_address: Address, to_token_address: Address, web3: Web3,
15 | account_address: Address) -> int:
16 |
17 | pool_address = get_pool(web3, from_token_address, to_token_address)
18 | utils = Utils()
19 | pool_contract = utils.load_contract(pool_address, web3, 'classic_pool_syncswap_data')
20 | amount_out = pool_contract.functions.getAmountOut(
21 | Web3.to_checksum_address(from_token_address),
22 | amount,
23 | account_address
24 | ).call()
25 |
26 | return amount_out
27 |
28 |
29 | def get_pool(web3: Web3, from_token_address: str, to_token_address: str) -> str:
30 | if from_token_address == '0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4' and \
31 | to_token_address == '0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df' \
32 | or from_token_address == '0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df' and \
33 | to_token_address == '0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4':
34 | factory_address = '0x5b9f21d407F35b10CbfDDca17D5D84b129356ea3'
35 | else:
36 | factory_address = '0x37BAc764494c8db4e54BDE72f6965beA9fa0AC2d'
37 | classic_pool_factory = web3.eth.contract(
38 | address=Web3.to_checksum_address(factory_address),
39 | abi=Utils.load_abi('classic_pool_factory_address'))
40 | pool_address = classic_pool_factory.functions.getPool(Web3.to_checksum_address(from_token_address),
41 | Web3.to_checksum_address(to_token_address)).call()
42 |
43 | return pool_address
44 |
45 |
46 | def create_swap_tx(from_token: str, contract: Contract, amount_out: int, from_token_address: str,
47 | to_token_address: str, account_address: Address, amount: int, web3: Web3) -> TxParams:
48 | pool_address = get_pool(web3, from_token_address, to_token_address)
49 | if pool_address == "0x0000000000000000000000000000000000000000":
50 | logger.error('Pool does not exist')
51 | return
52 |
53 | web3.middleware_onion.inject(geth_poa_middleware, layer=0)
54 | swap_data = encode(
55 | ["address", "address", "uint8"],
56 | [Web3.to_checksum_address(from_token_address), account_address, 1]
57 | )
58 | native_eth_address = "0x0000000000000000000000000000000000000000"
59 | steps = [{
60 | "pool": pool_address,
61 | "data": swap_data,
62 | "callback": native_eth_address,
63 | "callbackData": '0x'
64 | }]
65 | paths = [{
66 | "steps": steps,
67 | "tokenIn": Web3.to_checksum_address(
68 | from_token_address) if from_token.lower() != 'eth' else Web3.to_checksum_address(
69 | native_eth_address),
70 | "amountIn": amount,
71 | }]
72 |
73 | tx = contract.functions.swap(
74 | paths,
75 | int(amount_out * (1 - SLIPPAGE)),
76 | int(web3.eth.get_block('latest').timestamp) + 1200
77 | ).build_transaction({
78 | 'from': account_address,
79 | 'value': amount if from_token.lower() == 'eth' else 0,
80 | 'nonce': web3.eth.get_transaction_count(account_address),
81 | 'gasPrice': web3.eth.gas_price,
82 | })
83 | return tx
84 |
85 |
86 | def create_liquidity_tx(from_token: str, contract: Contract, to_token_address: str,
87 | account_address: Address, amount: int, web3: Web3, from_token_address) -> TxParams:
88 | pool_address = get_pool(web3, from_token_address, to_token_address)
89 | if pool_address == "0x0000000000000000000000000000000000000000":
90 | logger.error('Pool does not exist')
91 | return
92 |
93 | native_eth_address = "0x0000000000000000000000000000000000000000"
94 |
95 | callback = native_eth_address
96 | data = encode(
97 | ["address"],
98 | [account_address]
99 | )
100 |
101 | tx = contract.functions.addLiquidity2(
102 | Web3.to_checksum_address(pool_address),
103 | [(Web3.to_checksum_address(to_token_address), 0),
104 | (Web3.to_checksum_address(callback), amount)] if from_token.lower() == 'eth' else [
105 | (Web3.to_checksum_address(from_token_address), amount)],
106 | data,
107 | 0,
108 | callback,
109 | '0x'
110 | ).build_transaction({
111 | 'from': account_address,
112 | 'value': amount if from_token.lower() == 'eth' else 0,
113 | 'nonce': web3.eth.get_transaction_count(account_address),
114 | 'gasPrice': web3.eth.gas_price,
115 | })
116 | return tx
117 |
118 |
119 | def create_liquidity_remove_tx(web3: Web3, contract: Contract, from_token_pair_address: str, amount: int,
120 | account_address: Address, token: str) -> TxParams:
121 | from_token_address = tokens[token]
122 | pool_address = get_pool(web3, '0x37BAc764494c8db4e54BDE72f6965beA9fa0AC2d', from_token_address,
123 | from_token_pair_address)
124 |
125 | data = encode(
126 | ["address", "uint8"],
127 | [account_address, 1]
128 | )
129 |
130 | tx = contract.functions.burnLiquidity(
131 | Web3.to_checksum_address(pool_address),
132 | amount,
133 | data,
134 | [0, 0],
135 | "0x0000000000000000000000000000000000000000",
136 | '0x'
137 |
138 | ).build_transaction({
139 | 'from': account_address,
140 | 'nonce': web3.eth.get_transaction_count(account_address),
141 | 'gasPrice': web3.eth.gas_price,
142 | })
143 | return tx
144 |
--------------------------------------------------------------------------------
/src/modules/swaps/wrapper/eth_wrapper.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 | import random
3 |
4 | from loguru import logger
5 |
6 | from src.modules.swaps.wrapper.transaction_data import create_wrap_tx
7 | from src.utils.wrappers.decorators import retry
8 | from src.database.utils import DataBaseUtils
9 | from src.utils.user.account import Account
10 | from src.utils.data.tokens import tokens
11 | from config import USE_DATABASE
12 |
13 |
14 | class Wrapper(Account):
15 | def __init__(self, private_key: str, action: str, amount: Union[float, List[float]], use_all_balance: bool,
16 | use_percentage: bool, percentage_to_wrap: Union[float, List[float]]) -> None:
17 |
18 | super().__init__(private_key)
19 |
20 | self.action = action
21 | if isinstance(amount, List):
22 | self.amount = round(random.uniform(amount[0], amount[1]), 7)
23 | elif isinstance(amount, float):
24 | self.amount = amount
25 | else:
26 | logger.error(f'amount must be List[float] of float. Got {type(amount)}')
27 | return
28 |
29 | self.use_all_balance = use_all_balance
30 | self.use_percentage = use_percentage
31 |
32 | if isinstance(percentage_to_wrap, List):
33 | self.percentage_to_wrap = random.uniform(percentage_to_wrap[0], percentage_to_wrap[1])
34 | elif isinstance(percentage_to_wrap, float):
35 | self.percentage_to_wrap = percentage_to_wrap
36 | else:
37 | logger.error(f'percentage_to_wrap must be List[float] or float. Got {type(percentage_to_wrap)}')
38 | return
39 |
40 | if self.action.lower() == 'wrap':
41 | self.token = 'ETH'
42 | self.to_token = 'WETH'
43 | else:
44 | self.token = 'WETH'
45 | self.to_token = 'ETH'
46 |
47 | self.db_utils = DataBaseUtils('swap')
48 |
49 | def __repr__(self) -> str:
50 | return f'{self.__class__.__name__}: {self.account_address} | {"ETH => WETH" if self.action.lower() == "wrap" else "WETH => ETH"}'
51 |
52 | @retry()
53 | async def wrap(self) -> None:
54 | balance = self.get_wallet_balance('ETH' if self.action.lower() == 'wrap' else 'WETH', tokens['ETH'])
55 |
56 | if balance == 0:
57 | self.logger.error(f"🅾️ | Your balance is 0 | {self.account_address}")
58 | return
59 |
60 | amount = int(self.amount * 10 ** 18)
61 |
62 | if self.use_all_balance is True:
63 | if self.action.lower() == 'unwrap':
64 | amount = balance
65 | elif self.action.lower() == 'wrap':
66 | self.logger.error(f'You can not use use_all_balance = True to wrap ETH. Using amount_from, amount_to.')
67 | if self.use_percentage:
68 | amount = int(balance * self.percentage_to_wrap)
69 |
70 | tx = create_wrap_tx(self.account_address, self.token, self.web3, amount)
71 |
72 | tx_hash = self.sign_transaction(tx)
73 |
74 | self.logger.success(
75 | f'Successfully {"unwrapped" if self.action.lower() == "unwrap" else "wrapped"} {amount / 10 ** 18} {"WETH => ETH" if self.action.lower() == "unwrap" else "ETH => WETH"} | TX: https://blockscout.scroll.io/tx/{tx_hash}'
76 | )
77 | if USE_DATABASE:
78 | await self.db_utils.add_to_db(self.account_address, tx_hash, 'Wrapping', amount * 1e-18, self.token,
79 | self.to_token)
80 |
--------------------------------------------------------------------------------
/src/modules/swaps/wrapper/transaction_data.py:
--------------------------------------------------------------------------------
1 | from web3.types import TxParams
2 | from eth_typing import Address
3 | from web3 import Web3
4 |
5 | from src.utils.data.tokens import tokens
6 | from src.utils.user.utils import Utils
7 |
8 |
9 | def create_wrap_tx(account_address: Address, from_token: str, web3: Web3, amount: int) -> TxParams:
10 | contract = web3.eth.contract(address=tokens['ETH'], abi=Utils.load_abi('eth'))
11 |
12 | if from_token.lower() == 'eth':
13 | tx = contract.functions.deposit().build_transaction({
14 | 'value': amount,
15 | 'nonce': web3.eth.get_transaction_count(account_address),
16 | 'from': account_address,
17 | 'gasPrice': web3.eth.gas_price,
18 | })
19 | else:
20 | tx = contract.functions.withdraw(amount).build_transaction({
21 | 'value': 0,
22 | 'nonce': web3.eth.get_transaction_count(account_address),
23 | 'from': account_address,
24 | 'gasPrice': web3.eth.gas_price,
25 | })
26 |
27 | return tx
28 |
--------------------------------------------------------------------------------
/src/modules/swaps/zebra/utils/transaction_data.py:
--------------------------------------------------------------------------------
1 | from time import time
2 |
3 | from web3.contract import Contract
4 | from web3.types import TxParams
5 | from eth_typing import Address
6 | from web3 import Web3
7 |
8 | from config import SLIPPAGE
9 |
10 |
11 | def get_amount_out(contract: Contract, amount: int, from_token_address: Address,
12 | to_token_address: Address) -> int:
13 | amount_out = contract.functions.getAmountsOut(
14 | amount,
15 | [from_token_address, to_token_address]
16 | ).call()
17 | return amount_out[1]
18 |
19 |
20 | def create_swap_tx(from_token: str, contract: Contract, amount_out: int, from_token_address: str,
21 | to_token_address: str, account_address: Address, amount: int, web3: Web3) -> TxParams:
22 | if from_token.lower() == 'eth':
23 | tx = contract.functions.swapExactETHForTokens(
24 | int(amount_out * (1 - SLIPPAGE)),
25 | [web3.to_checksum_address(from_token_address), web3.to_checksum_address(to_token_address)],
26 | account_address,
27 | int(time() + 1200)
28 | ).build_transaction({
29 | 'value': amount if from_token.lower() == 'eth' else 0,
30 | 'nonce': web3.eth.get_transaction_count(account_address),
31 | 'from': account_address,
32 | 'gasPrice': web3.eth.gas_price,
33 | })
34 | else:
35 | tx = contract.functions.swapExactTokensForETH(
36 | amount,
37 | int(amount_out * (1 - SLIPPAGE)),
38 | [web3.to_checksum_address(from_token_address), web3.to_checksum_address(to_token_address)],
39 | account_address,
40 | int(time() + 1200)
41 | ).build_transaction({
42 | 'value': amount if from_token.lower() == 'eth' else 0,
43 | 'nonce': web3.eth.get_transaction_count(account_address),
44 | 'from': account_address,
45 | 'gasPrice': web3.eth.gas_price,
46 | })
47 | return tx
48 |
--------------------------------------------------------------------------------
/src/modules/swaps/zebra/zebra.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List
2 |
3 | from web3.contract import Contract
4 | from eth_typing import Address
5 | from web3 import Web3
6 |
7 | from src.utils.base_swap import BaseSwap
8 | from src.utils.data.types import Types
9 |
10 | from src.utils.data.contracts import (
11 | contracts,
12 | abi_names,
13 | )
14 |
15 | from src.modules.swaps.zebra.utils.transaction_data import (
16 | get_amount_out,
17 | create_swap_tx,
18 | )
19 |
20 |
21 | class ZebraSwap(BaseSwap):
22 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]],
23 | amount: Union[float, List[float]], use_percentage: bool, swap_percentage: Union[float, List[float]],
24 | swap_all_balance: bool) -> None:
25 | contract_address = contracts['zebra']
26 | abi_name = abi_names['zebra']
27 | dex_name = self.__class__.__name__
28 |
29 | super().__init__(private_key, from_token, to_token, amount, use_percentage, swap_percentage, swap_all_balance,
30 | contract_address, abi_name, dex_name)
31 |
32 | def __repr__(self) -> str:
33 | return f'{self.__class__.__name__}: {self.account_address} | {self.from_token} => {self.to_token}'
34 |
35 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
36 | to_token_address: Address) -> Types.AmountOut:
37 | return get_amount_out(contract, amount, from_token_address, to_token_address)
38 |
39 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
40 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
41 | web3: Web3) -> Types.SwapTransaction:
42 | return create_swap_tx(from_token, contract, amount_out, from_token_address, to_token_address,
43 | account_address, amount, web3)
44 |
--------------------------------------------------------------------------------
/src/utils/base_bridge.py:
--------------------------------------------------------------------------------
1 | from typing import Union, List, Optional
2 | from abc import ABC, abstractmethod
3 | from fractions import Fraction
4 | from asyncio import sleep
5 | import random
6 |
7 | from web3.contract import Contract
8 | from eth_typing import Address
9 | from web3 import Web3
10 |
11 | from src.modules.bridges.main_bridge.utils.transaction_data import claim_eth
12 | from src.utils.data.chains import chain_mapping
13 | from src.utils.wrappers.decorators import retry
14 | from src.database.utils import DataBaseUtils
15 | from src.utils.user.account import Account
16 | from src.utils.data.types import Types
17 | from config import USE_DATABASE
18 |
19 |
20 | class BaseBridge(ABC, Account):
21 | def __init__(self, private_key: str, amount: Union[float, List[float]], use_percentage: bool,
22 | bridge_percentage: Union[float, List[float]], contract_address: Optional[str], abi_name: Optional[str],
23 | dex_name: str, rpc: Optional[str], scan: str = 'https://etherscan.io/tx',
24 | from_chain: Optional[str] = None, to_chain: Optional[str] = None, code: Optional[int] = None,
25 | claim_eth: Optional[bool] = None) -> None:
26 |
27 | super().__init__(private_key, rpc)
28 |
29 | self.private_key = private_key
30 |
31 | if isinstance(amount, List):
32 | self.amount = round(random.uniform(amount[0], amount[1]), 7)
33 | else:
34 | self.amount = amount
35 | if isinstance(bridge_percentage, List):
36 | self.bridge_percentage = random.uniform(bridge_percentage[0], bridge_percentage[1])
37 | else:
38 | self.bridge_percentage = bridge_percentage
39 | self.use_percentage = use_percentage
40 | self.contract_address = contract_address
41 | self.abi_name = abi_name
42 | self.dex_name = dex_name
43 | self.scan = scan
44 | self.from_chain = from_chain
45 | self.to_chain = to_chain
46 | self.code = code
47 | self.claim_eth = claim_eth
48 | self.db_utils = DataBaseUtils('bridge')
49 |
50 | @retry()
51 | async def bridge(self) -> None:
52 | contract = None
53 | if not self.dex_name == 'Owlto' or not self.dex_name == 'Orbiter':
54 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
55 | balance = self.get_wallet_balance('ETH', '...')
56 |
57 | if balance == 0:
58 | self.logger.error(f'🅾️ | Your balance is 0 | {self.account_address}')
59 | return
60 |
61 | to_chain_account = Account(self.private_key, chain_mapping[self.to_chain.lower()].rpc)
62 | balance_before_bridge = to_chain_account.get_wallet_balance('ETH', '...')
63 |
64 | if self.use_percentage:
65 | amount = int(balance * self.bridge_percentage)
66 | amount = round(amount, 7)
67 | else:
68 | amount = self.create_amount('ETH', '...', self.web3, self.amount)
69 |
70 | amount = int(str(amount)[:-7] + '0000000')
71 |
72 | if self.dex_name == 'Owlto' or self.dex_name == 'Orbiter':
73 | amount = int(str(Fraction(amount))[:-4] + str(self.code))
74 |
75 | if amount > balance:
76 | self.logger.error(f'📉 | Not enough balance for wallet {self.account_address}')
77 | return
78 |
79 | eligibility, min_limit, max_limit = self.check_eligibility(amount)
80 | if eligibility is False:
81 | self.logger.error(f'Limits error. {min_limit} < amount < {max_limit}. Got {amount / 10 ** 18} ETH')
82 | return
83 |
84 | tx = self.create_bridge_tx(contract, amount, self.web3, self.account_address)
85 | if self.dex_name == 'Orbiter' or self.dex_name == 'Owlto':
86 | gas_limit = self.web3.eth.estimate_gas(tx)
87 | tx.update({'gas': gas_limit})
88 |
89 | tx_hash = self.sign_transaction(tx)
90 | self.logger.success(
91 | f'Successfully bridged {amount / 10 ** 18} ETH tokens | TX: {self.scan}/{tx_hash}'
92 | )
93 | if USE_DATABASE:
94 | await self.db_utils.add_to_db(self.account_address, tx_hash, self.dex_name, amount / 10 ** 18)
95 |
96 | if self.dex_name == 'MainBridge' and self.from_chain == 'SCROLL' and self.claim_eth:
97 | self.logger.debug('Claiming ETH...')
98 | await claim_eth(tx_hash, self.private_key)
99 |
100 | await self.wait_for_bridge(to_chain_account, balance_before_bridge)
101 |
102 | async def wait_for_bridge(self, account: Account, balance_before_bridge: int) -> None:
103 | self.logger.info(f'Waiting for ETH to arrive in {self.to_chain.upper()}...')
104 | while True:
105 | try:
106 | balance = account.get_wallet_balance('ETH', '...')
107 | if balance > balance_before_bridge:
108 | self.logger.success(f'ETH has arrived | [{self.account_address}]')
109 | break
110 | await sleep(20)
111 | except Exception as ex:
112 | self.logger.error(f'Something went wrong {ex}')
113 | await sleep(10)
114 | continue
115 |
116 | @abstractmethod
117 | def create_bridge_tx(self, contract: Contract, amount: int, web3: Web3, account_address: Address
118 | ) -> Types.BridgeTransaction:
119 | """Create a transaction for bridge"""
120 |
121 | @abstractmethod
122 | def check_eligibility(self, amount: int) -> Union[bool, tuple[bool, float, int]]:
123 | """Check if eligible for bridge"""
124 |
--------------------------------------------------------------------------------
/src/utils/base_liquidity.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 | from asyncio import sleep
3 | import random
4 |
5 | from typing import (
6 | Union,
7 | List,
8 | Any,
9 | )
10 |
11 | from web3.contract import Contract
12 | from eth_typing import Address
13 | from web3 import Web3
14 |
15 | from src.database.utils import DataBaseUtils
16 | from src.utils.wrappers.decorators import retry
17 | from src.utils.user.account import Account
18 | from src.utils.data.tokens import tokens
19 | from src.utils.data.types import Types
20 |
21 | from config import USE_DATABASE
22 |
23 |
24 | class BaseLiquidity(ABC, Account):
25 | def __init__(self, private_key: str, token: str, token2: str, amount: Union[float, List[float]],
26 | use_percentage: bool, liquidity_percentage: Union[float, List[float]],
27 | contract_address: str, abi_name: str, dex_name: str) -> None:
28 |
29 | super().__init__(private_key)
30 |
31 | self.private_key = private_key
32 | self.token = token
33 |
34 | self.token2 = token2
35 | if isinstance(token2, list):
36 | self.token2 = random.choice(token2)
37 |
38 | if isinstance(amount, List):
39 | self.amount = round(random.uniform(amount[0], amount[1]), 7)
40 | elif isinstance(amount, float):
41 | self.amount = amount
42 | else:
43 | self.logger.error(f'amount must be float or List[float]. Got {type(amount)}')
44 | return
45 | self.use_percentage = use_percentage
46 | if isinstance(liquidity_percentage, List):
47 | self.liquidity_percentage = random.uniform(liquidity_percentage[0], liquidity_percentage[1])
48 | elif isinstance(liquidity_percentage, float):
49 | self.liquidity_percentage = liquidity_percentage
50 | else:
51 | self.logger.error(f'liquidity_percentage must be float or List[float]. Got {type(liquidity_percentage)}')
52 | return
53 | self.contract_address = contract_address
54 | self.abi_name = abi_name
55 | self.dex_name = dex_name
56 | self.db_utils = DataBaseUtils('liquidity')
57 |
58 | @retry()
59 | async def add_liquidity(self) -> None:
60 | from_token_address, to_token_address = tokens[self.token.upper()], tokens[self.token2.upper()]
61 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
62 | amount = self.create_amount(self.token, from_token_address, self.web3, self.amount)
63 | balance = self.get_wallet_balance(self.token, from_token_address)
64 |
65 | if self.use_percentage:
66 | amount = int(balance * self.liquidity_percentage)
67 |
68 | if amount > balance:
69 | self.logger.error(f'Not enough balance for wallet | {self.account_address}')
70 | return
71 |
72 | await self.approve_token(amount, self.private_key, from_token_address, self.contract_address,
73 | self.account_address, self.web3)
74 |
75 | await self.approve_token(amount, self.private_key, to_token_address, self.contract_address,
76 | self.account_address, self.web3)
77 |
78 | amount_out = 0
79 | if self.dex_name != 'SyncSwapLiquidity':
80 | while True:
81 | stable_balance = self.get_wallet_balance(self.token2, to_token_address)
82 | amount_out = self.get_amount_out(contract, amount, Web3.to_checksum_address(from_token_address),
83 | Web3.to_checksum_address(to_token_address))
84 | if amount_out > stable_balance:
85 | self.logger.error(f'Not enough {self.token2.upper()} balance for wallet | {self.account_address}')
86 | self.logger.info(f'Swapping {amount / 10 ** 18} ETH => {self.token2.upper()}')
87 | swap = await self.get_swap_instance(self.private_key, self.token, self.token2, amount / 10 ** 18)
88 | await swap.swap()
89 | sleep_time = random.randint(45, 75)
90 | self.logger.info(f'Sleeping {sleep_time} seconds...')
91 | await sleep(sleep_time)
92 | continue
93 | break
94 |
95 | tx = self.create_liquidity_tx(self.token, contract, amount_out, from_token_address, to_token_address,
96 | self.account_address, amount, self.web3)
97 |
98 | tx_hash = self.sign_transaction(tx)
99 |
100 | self.logger.success(
101 | f'Successfully added liquidity with {amount / 10 ** 18} {self.token}, {amount_out / 10 ** 18} {self.token2.upper()} | TX: https://blockscout.scroll.io/tx/{tx_hash}'
102 | )
103 | if USE_DATABASE:
104 | if self.token.lower() == 'eth':
105 | value_amount = self.amount
106 | elif self.token2.lower() == 'eth':
107 | value_amount = amount_out * 1e-18
108 | else:
109 | value_amount = self.get_amount_out(contract, amount, Web3.to_checksum_address(from_token_address),
110 | Web3.to_checksum_address(
111 | '0x5300000000000000000000000000000000000004')) * 1e-18
112 |
113 | await self.db_utils.add_to_db(self.account_address, f'https://blockscout.scroll.io/tx/{tx_hash}',
114 | self.dex_name,
115 | value_amount * 2 if self.dex_name != 'SyncSwap' else value_amount,
116 | self.token, self.token2)
117 |
118 | @abstractmethod
119 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
120 | to_token_address: Address) -> Types.AmountOut:
121 | """Get the stable amount for liquidity."""
122 |
123 | @abstractmethod
124 | def create_liquidity_tx(self, from_token: str, contract: Contract, amount_out: int, from_token_address: str,
125 | to_token_address: str, account_address: Address, amount: int,
126 | web3: Web3) -> Types.LiquidityTransaction:
127 | """Create a transaction for liquidity."""
128 |
129 | @abstractmethod
130 | async def get_swap_instance(self, private_key: str, token: str, token2: str, amount: float) -> Any:
131 | """Get an instance for swap if not enough stable balance for liquidity."""
132 |
--------------------------------------------------------------------------------
/src/utils/base_liquidity_remove.py:
--------------------------------------------------------------------------------
1 | import random
2 | from abc import ABC, abstractmethod
3 | from typing import Union, List
4 |
5 | from web3.contract import Contract
6 | from eth_typing import Address
7 | from loguru import logger
8 | from web3 import Web3
9 |
10 | from src.utils.data.types import Types
11 | from src.utils.user.account import Account
12 | from src.utils.wrappers.decorators import retry
13 |
14 | from src.utils.data.tokens import (
15 | liquidity_tokens,
16 | tokens,
17 | )
18 |
19 |
20 | class BaseLiquidityRemove(ABC, Account):
21 | def __init__(self, private_key: str, from_token_pair: Union[str, List[str]], remove_all: bool,
22 | removing_percentage: float, contract_address: str, abi_name: str, pool_name: str,
23 | token: str = None) -> None:
24 |
25 | super().__init__(private_key)
26 |
27 | self.private_key = private_key
28 |
29 | if isinstance(from_token_pair, List):
30 | self.from_token_pair = random.choice(from_token_pair)
31 | elif isinstance(from_token_pair, str):
32 | self.from_token_pair = from_token_pair
33 | else:
34 | self.logger.error(f'from_token_pair must be str or list[str]. Got {type(from_token_pair)}')
35 |
36 | self.remove_all = remove_all
37 | self.removing_percentage = removing_percentage
38 | self.contract_address = contract_address
39 | self.abi_name = abi_name
40 | self.pool_name = pool_name
41 | self.token = token
42 |
43 | @retry()
44 | async def remove_liquidity(self) -> None:
45 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
46 | liquidity_token_address = liquidity_tokens[self.pool_name]['ETH' if self.token is None else self.token.upper()][
47 | self.from_token_pair.upper()]
48 | balance = self.get_wallet_balance('...', liquidity_token_address)
49 |
50 | if balance == 0:
51 | logger.debug("You don't have any tokens to withdraw")
52 | return
53 |
54 | amount = self.create_liquidity_remove_amount(balance, self.remove_all, self.removing_percentage)
55 |
56 | await self.approve_token(amount, self.private_key, liquidity_token_address, self.contract_address,
57 | self.account_address, self.web3)
58 |
59 | tx = self.create_liquidity_remove_tx(self.web3, contract, tokens[self.from_token_pair.upper()],
60 | amount, self.account_address, token=self.token)
61 |
62 | tx_hash = self.sign_transaction(tx)
63 |
64 | logger.success(
65 | f'Removed {"all" if self.remove_all else f"{int(self.removing_percentage * 100)}%"} {self.from_token_pair} tokens from {self.pool_name} pool | TX: https://blockscout.scroll.io/tx/{tx_hash}'
66 | )
67 |
68 | @abstractmethod
69 | def create_liquidity_remove_tx(self, web3: Web3, contract: Contract, from_token_pair_address: str,
70 | amount: int, account_address: Address, token: str = None
71 | ) -> Types.LiquidityRemoveTransaction:
72 | """Create a transaction for liquidity removal."""
73 |
--------------------------------------------------------------------------------
/src/utils/base_mint.py:
--------------------------------------------------------------------------------
1 | from abc import (
2 | abstractmethod,
3 | ABC,
4 | )
5 |
6 | from web3.contract import Contract
7 |
8 | from src.utils.wrappers.decorators import retry
9 | from src.database.utils import DataBaseUtils
10 | from src.utils.user.account import Account
11 | from src.utils.data.types import Types
12 | from config import USE_DATABASE
13 |
14 |
15 | class BaseMint(ABC, Account):
16 | def __init__(self, private_key: str, contract_address: str, abi_name: str, nft_name: str,
17 | amount: float = None) -> None:
18 | super().__init__(private_key)
19 | self.db_utils = DataBaseUtils('mint')
20 | self.contract_address = contract_address
21 | self.abi_name = abi_name
22 | self.nft_name = nft_name
23 | self.amount = amount
24 |
25 | @retry()
26 | async def mint(self) -> None:
27 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
28 | balance = self.get_wallet_balance('ETH', '...')
29 |
30 | if balance == 0:
31 | self.logger.error(f'🅾️ | Your balance is 0 | {self.account_address}')
32 | return
33 |
34 | tx = self.create_mint_tx(contract)
35 | if tx is None:
36 | return
37 |
38 | tx_hash = self.sign_transaction(tx)
39 | confirmed = self.wait_until_tx_finished(tx_hash)
40 |
41 | if confirmed:
42 | self.logger.success(
43 | f'Successfully minted NFT | TX: https://scrollscan.com/tx/{tx_hash}'
44 | )
45 | if USE_DATABASE:
46 | await self.db_utils.add_to_db(self.account_address, f'https://scrollscan.com/tx/{tx_hash}',
47 | self.nft_name, self.amount)
48 |
49 | @abstractmethod
50 | def create_mint_tx(self, contract: Contract) -> Types.MintTransaction:
51 | """Create a transaction for mint."""
52 |
--------------------------------------------------------------------------------
/src/utils/base_swap.py:
--------------------------------------------------------------------------------
1 | from abc import ABC, abstractmethod
2 | from typing import Union, List, Optional
3 | import random
4 |
5 | from web3.contract import Contract
6 | from eth_typing import Address
7 | from web3 import Web3
8 |
9 | from src.utils.wrappers.decorators import retry
10 | from src.database.utils import DataBaseUtils
11 | from src.utils.user.account import Account
12 | from src.utils.data.tokens import tokens
13 | from src.utils.data.types import Types
14 | from config import USE_DATABASE
15 |
16 |
17 | class BaseSwap(ABC, Account):
18 | def __init__(self, private_key: str, from_token: str, to_token: Union[str, List[str]], amount: Union[float, List[float]],
19 | use_percentage: bool, swap_percentage: Union[float, List[float]], swap_all_balance: bool,
20 | contract_address: str, abi_name: str, dex_name: str) -> None:
21 |
22 | super().__init__(private_key)
23 |
24 | self.private_key = private_key
25 | self.from_token = from_token
26 | if isinstance(to_token, List):
27 | self.to_token = random.choice(to_token)
28 | elif isinstance(to_token, str):
29 | self.to_token = to_token
30 | else:
31 | self.logger.error(f'to_token must be str or list[str]. Got {type(to_token)}')
32 | return
33 | if isinstance(amount, List):
34 | self.amount = round(random.uniform(amount[0], amount[1]), 7)
35 | else:
36 | self.amount = amount
37 | self.use_percentage = use_percentage
38 | if isinstance(swap_percentage, List):
39 | self.swap_percentage = random.uniform(swap_percentage[0], swap_percentage[1])
40 | else:
41 | self.swap_percentage = swap_percentage
42 | self.swap_all_balance = swap_all_balance
43 | self.contract_address = contract_address
44 | self.abi_name = abi_name
45 | self.dex_name = dex_name
46 | self.db_utils = DataBaseUtils('swap')
47 | if self.use_percentage and self.swap_all_balance:
48 | self.logger.warning('You set use_percentage and swap_all_balance both True. Using swap_percentage.')
49 |
50 | @retry()
51 | async def swap(self) -> Optional[Union[bool, str]]:
52 | from_token_address, to_token_address = tokens[self.from_token.upper()], tokens[self.to_token.upper()]
53 | contract = self.load_contract(self.contract_address, self.web3, self.abi_name)
54 | balance = self.get_wallet_balance(self.from_token, from_token_address)
55 | amount = self.create_amount(self.from_token, from_token_address, self.web3, self.amount)
56 |
57 | if balance == 0:
58 | self.logger.error(f'🅾️ | Your balance is 0 | {self.account_address}')
59 | return 'ZeroBalance'
60 |
61 | if self.swap_all_balance is True and self.from_token.lower() == 'eth':
62 | self.logger.error(
63 | "You can't use swap_all_balance = True with ETH token. Using amount_from, amount_to")
64 | if self.swap_all_balance is True and self.from_token.lower() != 'eth':
65 | amount = balance
66 |
67 | if self.use_percentage is True:
68 | amount = int(balance * self.swap_percentage)
69 |
70 | if amount > balance:
71 | self.logger.error(f'📉 | Not enough balance for wallet {self.account_address}')
72 | return
73 |
74 | amount_out = self.get_amount_out(contract, amount, self.web3.to_checksum_address(from_token_address),
75 | self.web3.to_checksum_address(to_token_address))
76 |
77 | if self.from_token.lower() != 'eth':
78 | await self.approve_token(amount, self.private_key, from_token_address, self.contract_address,
79 | self.account_address, self.web3)
80 |
81 | tx = self.create_swap_tx(self.from_token, self.to_token, contract, amount_out, from_token_address,
82 | to_token_address, self.account_address, amount, self.web3)
83 |
84 | if tx is None:
85 | return
86 |
87 | try:
88 | tx_hash = self.sign_transaction(tx)
89 | confirmed = self.wait_until_tx_finished(tx_hash)
90 | except Exception as ex:
91 | self.logger.error(f'Something went wrong {ex}')
92 | return False
93 |
94 | if confirmed:
95 | self.logger.success(
96 | f'Successfully swapped {"all" if self.swap_all_balance is True and self.from_token.lower() != "eth" and self.use_percentage is False else f"{int(self.swap_percentage * 100)}%" if self.use_percentage is True else self.amount} {self.from_token} tokens => {self.to_token} | TX: https://blockscout.scroll.io/tx/{tx_hash}'
97 | )
98 |
99 | if USE_DATABASE:
100 | if self.from_token.lower() == 'eth':
101 | value_amount = self.amount
102 | elif self.to_token.lower() == 'eth':
103 | value_amount = amount_out * 1e-18
104 | else:
105 | value_amount = self.get_amount_out(contract, amount, Web3.to_checksum_address(from_token_address),
106 | Web3.to_checksum_address(
107 | '0x5300000000000000000000000000000000000004')) * 1e-18
108 |
109 | await self.db_utils.add_to_db(self.account_address, f'https://blockscout.scroll.io/tx/{tx_hash}',
110 | self.dex_name, value_amount, self.from_token, self.to_token)
111 | return True
112 | else:
113 | return False
114 |
115 | @abstractmethod
116 | def get_amount_out(self, contract: Contract, amount: int, from_token_address: Address,
117 | to_token_address: Address) -> Types.AmountOut:
118 | """Get the amount after swap."""
119 |
120 | @abstractmethod
121 | def create_swap_tx(self, from_token: str, to_token: str, contract: Contract, amount_out: int,
122 | from_token_address: str, to_token_address: str, account_address: Address, amount: int,
123 | web3: Web3) -> Types.SwapTransaction:
124 | """Create a transaction for swap."""
125 |
--------------------------------------------------------------------------------
/src/utils/data/chains.py:
--------------------------------------------------------------------------------
1 | class Chain:
2 | def __init__(self, chain_id: int, rpc: str, scan: str) -> None:
3 | self.chain_id = chain_id
4 | self.rpc = rpc
5 | self.scan = scan
6 |
7 |
8 | ETH = Chain(
9 | chain_id=1,
10 | rpc='https://rpc.ankr.com/eth',
11 | scan='https://etherscan.io/tx'
12 | )
13 |
14 | BASE = Chain(
15 | chain_id=8453,
16 | rpc='https://base.blockpi.network/v1/rpc/public',
17 | scan='https://basescan.org//tx'
18 | )
19 |
20 | ARB = Chain(
21 | chain_id=42161,
22 | rpc='https://arb1.arbitrum.io/rpc',
23 | scan='https://arbiscan.io/tx'
24 | )
25 |
26 | ERA = Chain(
27 | chain_id=324,
28 | rpc='https://1rpc.io/zksync2-era',
29 | scan='https://explorer.zksync.io/tx'
30 | )
31 |
32 | SCROLL = Chain(
33 | chain_id=534352,
34 | rpc='https://rpc.scroll.io',
35 | scan='https://blockscout.scroll.io/tx'
36 | )
37 |
38 | OP = Chain(
39 | chain_id=10,
40 | rpc='https://optimism.blockpi.network/v1/rpc/public',
41 | scan='https://optimistic.etherscan.io/tx'
42 | )
43 |
44 | LINEA = Chain(
45 | chain_id=59144,
46 | rpc='https://linea.blockpi.network/v1/rpc/public',
47 | scan='https://lineascan.build/tx'
48 | )
49 |
50 | chain_mapping = {
51 | 'base': BASE,
52 | 'eth': ETH,
53 | 'era': ERA,
54 | 'arb': ARB,
55 | 'scroll': SCROLL,
56 | 'op': OP,
57 | 'linea': LINEA
58 | }
59 |
60 | okx_chain_mapping = {
61 | 'ERC20': ETH,
62 | 'Arbitrum One': ARB,
63 | 'Optimism': OP,
64 | 'zkSync Era': ERA,
65 | 'Base': BASE,
66 | 'Linea': LINEA
67 | }
68 |
--------------------------------------------------------------------------------
/src/utils/data/contracts.py:
--------------------------------------------------------------------------------
1 | contracts = {
2 | 'skydrome': '0xAA111C62cDEEf205f70E6722D1E22274274ec12F',
3 | 'punkswap': '0x26cB8660EeFCB2F7652e7796ed713c9fB8373f8e',
4 | 'spacefi': '0x18b71386418A9FCa5Ae7165E31c385a5130011b6',
5 | 'zebra': '0x0122960d6e391478bfe8fb2408ba412d5600f621',
6 | 'syncswap': '0x80e38291e06339d10AAB483C65695D004dBD5C69',
7 | 'dmail': '0x47fbe95e981c0df9737b6971b451fb15fdc989d9',
8 | 'layerbank': '0xec53c830f4444a8a56455c6836b5d2aa794289aa',
9 | 'aave': {
10 | 'aave_contract': '0xff75a4b698e3ec95e608ac0f22a03b8368e05f5d',
11 | 'aave_weth': '0xf301805be1df81102c957f6d4ce29d2b8c056b2a'
12 | },
13 | 'l2pass': '0x0000049f63ef0d60abe49fdd8bebfa5a68822222',
14 | 'omnisea': '0x46ce46951d12710d85bc4fe10bb29c6ea5012077',
15 | 'rubyscore': '0xe10Add2ad591A7AC3CA46788a06290De017b9fB4',
16 | 'scroll_citizen': [
17 | "0xc519d9d47c003b6274e20cfe21d58fee1efa7a0e",
18 | "0x1249e38bb84aa3cbe6f4506a85b6831ef49ed48f",
19 | "0xcde5e31d0c7348161b76579a6e25b8874de91434",
20 | "0xd4eac5a09e5e8ac8e94f62e46b5d9e808e577d2e",
21 | "0x51c8b85aedb821712c7115f36d252018951c4b16",
22 | "0x6982d37e2bc0de66ce744a65a79c57926f11a947",
23 | "0xf4647c674e32506809f77cf3236ed8034e817cc9",
24 | "0x6b4772a613a63cbdb15c767bd604e9f5ecf60fcd",
25 | "0x4395df30ef87a2c23ab393fe0bf1f2d2ef6eefc1",
26 | "0x36c9724d98dc3f46676bf213da318e556bcc3d16",
27 | "0x80151e432f5c6d6c89427bceee6738bcc61e3fa6",
28 | "0xd4215d6aff866151c2df3ebed8ff0cc084b7d2cf",
29 | "0xde2fea1c76d1d08b0055b8ae6bc4ce8a31403192",
30 | "0xbdb2cd55421ecd520a04be90b6dee93689a203de",
31 | "0x65665e3275e2a122c61f953929ca13c1bb5a593b",
32 | "0x07e2f41b117b34dda4c7044242e903053a7ea025",
33 | "0x6de8a54d6771325e53e53e85aaf614392839caff",
34 | "0x9efd036f4f30d9802d4dc1b7ece292d2ef896883",
35 | "0x57324f9d28d0b89ec980b0b0c6a432c761faf6b2",
36 | "0x2ab5a55aac0df0087fb2b352372fe19e84f46041"
37 | ],
38 | 'zk_stars': [
39 | "0x609c2f307940b8f52190b6d3d3a41c762136884e",
40 | "0x16c0baa8a2aa77fab8d0aece9b6947ee1b74b943",
41 | "0xc5471e35533e887f59df7a31f7c162eb98f367f7",
42 | "0xf861f5927c87bc7c4781817b08151d638de41036",
43 | "0x954e8ac11c369ef69636239803a36146bf85e61b",
44 | "0xa576ac0a158ebdcc0445e3465adf50e93dd2cad8",
45 | "0x17863384c663c5f95e4e52d3601f2ff1919ac1aa",
46 | "0x4c2656a6d1c0ecac86f5024e60d4f04dbb3d1623",
47 | "0x4e86532cedf07c7946e238bd32ba141b4ed10c12",
48 | "0x6b9db0ffcb840c3d9119b4ff00f0795602c96086",
49 | "0x10d4749bee6a1576ae5e11227bc7f5031ad351e4",
50 | "0x373148e566e4c4c14f4ed8334aba3a0da645097a",
51 | "0xdacbac1c25d63b4b2b8bfdbf21c383e3ccff2281",
52 | "0x2394b22b3925342f3216360b7b8f43402e6a150b",
53 | "0xf34f431e3fc0ad0d2beb914637b39f1ecf46c1ee",
54 | "0x6f1e292302dce99e2a4681be4370d349850ac7c2",
55 | "0xa21fac8b389f1f3717957a6bb7d5ae658122fc82",
56 | "0x1b499d45e0cc5e5198b8a440f2d949f70e207a5d",
57 | "0xec9bef17876d67de1f2ec69f9a0e94de647fcc93",
58 | "0x5e6c493da06221fed0259a49beac09ef750c3de1"
59 | ]
60 | }
61 |
62 | abi_names = {
63 | 'skydrome': 'skydrome',
64 | 'punkswap': 'punkswap',
65 | 'syncswap': 'syncswap',
66 | 'spacefi': 'spacefi',
67 | 'dmail': 'dmail',
68 | 'layerbank': 'layerbank',
69 | 'aave': 'aave_abi',
70 | 'l2pass': 'l2pass_abi',
71 | 'omnisea': 'omnisea_abi',
72 | 'rubyscore': 'rubyscore_abi',
73 | 'scroll_citizen': 'scroll_citizen_abi',
74 | 'zkstars': 'zkstars_abi',
75 | 'zebra': 'zebra_abi'
76 | }
77 |
--------------------------------------------------------------------------------
/src/utils/data/helper.py:
--------------------------------------------------------------------------------
1 | from colorama import Fore
2 | from web3 import Web3
3 |
4 | from src.utils.data.mappings import module_handlers
5 |
6 | with open('config.py', 'r', encoding='utf-8-sig') as file:
7 | module_config = file.read()
8 |
9 | exec(module_config)
10 |
11 | with open('wallets.txt', 'r', encoding='utf-8-sig') as file:
12 | private_keys = [line.strip() for line in file]
13 |
14 | patterns = {}
15 | web3 = Web3(Web3.HTTPProvider('https://rpc.scroll.io'))
16 |
17 | for module in module_handlers:
18 | if globals().get(module):
19 | patterns[module] = 'On'
20 | else:
21 | patterns[module] = 'Off'
22 |
23 | print(Fore.BLUE + f'Loaded {len(private_keys)} wallets:')
24 | print('\033[39m')
25 |
26 | for private_key in private_keys:
27 | print(web3.eth.account.from_key(private_key).address)
28 |
29 | print(f'----------------------------------------Modules--------------------------------------------')
30 |
31 | for pattern, value in patterns.items():
32 | if value == 'Off':
33 | print("\033[31m {}".format(f'{pattern} = {value}'))
34 | else:
35 | print("\033[32m {}".format(f'{pattern} = {value}'))
36 | print('\033[39m')
37 |
38 | print('Created by | https://t.me/cryptoscripts')
39 | print('Donations (Any EVM) | 0x763cDEa4a54991Cd85bFAd1FD47E9c175f53090B')
40 | active_module = [module for module, value in patterns.items() if value == 'On']
41 |
--------------------------------------------------------------------------------
/src/utils/data/mappings.py:
--------------------------------------------------------------------------------
1 | from src.utils.runner import *
2 |
3 | module_handlers = {
4 | 'main_bridge': process_main_bridge,
5 | 'owl_bridge': process_owl_bridge,
6 | 'orbiter_bridge': process_orbiter_bridge,
7 | 'skydrome_swap': process_skydrome_swap,
8 | 'skydrome_liquidity': process_skydrome_liquidity,
9 | 'skydrome_liquidity_remove': process_skydrome_liquidity_remove,
10 | 'specefi_swap': process_spacefi_swap,
11 | 'spacefi_liquidity': process_spacefi_liquidity,
12 | 'spacefi_liquidity_remove': process_spacefi_liquidity_remove,
13 | 'punk_swap': process_punk_swap,
14 | 'punk_swap_liquidity': process_punk_swap_liquidity,
15 | 'punk_swap_liquidity_remove': process_punk_swap_liquidity_remove,
16 | 'syncswap_swap': process_sync_swap_swap,
17 | 'syncswap_liquidity': process_sync_swap_liquidity,
18 | 'syncswap_liquidity_remove': process_sync_swap_liquidity_remove,
19 | 'swap_all_to_eth': process_swap_all_to_eth,
20 | 'random_dex_swap': process_random_dex_swap,
21 | 'wrapper': process_wrapper,
22 | 'okx_withdraw': process_okx_withdrawal,
23 | 'okx_deposit': process_okx_deposit,
24 | 'dmail': process_dmail,
25 | 'zerius': process_zerius_mint_bridge,
26 | 'deploy_contract': process_deploy,
27 | 'layerbank_deposit': process_layerbank_deposit,
28 | 'layerbank_withdraw': process_layerbank_withdraw,
29 | 'aave_deposit': process_deposit_aave,
30 | 'aave_withdraw': process_withdraw_aave,
31 | 'l2pass': process_l2pass_mint,
32 | 'omnisea': process_omnisea_create,
33 | 'rubyscore': process_rubyscore_voting,
34 | 'scroll_citizen': process_scroll_citizen_mint,
35 | 'zk_stars': process_zkstars_mint,
36 | 'zebra_swap': process_zebra_swap,
37 | 'multi_approve': process_multi_approve,
38 | 'random_add_liquidity': process_random_liquidity
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils/data/tokens.py:
--------------------------------------------------------------------------------
1 | tokens = {
2 | 'ETH': '0x5300000000000000000000000000000000000004',
3 | 'WETH': '0x5300000000000000000000000000000000000004',
4 | 'USDC': '0x06eFdBFf2a14a7c8E15944D1F4A48F9F95F663A4',
5 | 'USDT': '0xf55BEC9cafDbE8730f096Aa55dad6D22d44099Df',
6 | 'PUNK': '0xDdEB23905F6987d5f786A93C00bBED3d97Af1ccc',
7 | 'DAI': '0xca77eb3fefe3725dc33bccb54edefc3d9f764f97',
8 | 'WBTC': '0x3c1bca5a656e69edcd0d4e36bebb3fcdaca60cf1',
9 | 'SYS': '0x1467b62a6ae5cdcb10a6a8173cfe187dd2c5a136',
10 | 'ITP': '0x2b1d36f5b61addaf7da7ebbd11b35fd8cfb0de31',
11 | 'LUSD': '0xedeabc3a1e7d21fe835ffa6f83a710c70bb1a051',
12 | 'wstETH': '0xf610a9dfb7c89644979b4a0f27063e9e7d7cda32',
13 | 'rETH': '0x53878b874283351d26d206fa512aece1bef6c0dd',
14 | 'wrsETH': '0xa25b25548b4c98b0c7d3d27dca5d5ca743d68b7f',
15 | 'pxETH': '0x9e0d7d79735e1c63333128149c7b616a0dc0bbdb'
16 | }
17 |
18 | liquidity_tokens = {
19 | 'PunkSwap': {
20 | 'ETH': {
21 | 'USDC': '0x6562e87944e4D6cCF9839C662db32E6b19f72cDe',
22 | 'USDT': '0xB12abB5bcB50c2aA6f1B54447046640010B33933',
23 | },
24 | 'USDC': {
25 | 'USDT': '0x2307DBafED1464605E5CfC7fbC7aE761Aa527f45',
26 | }
27 | },
28 | 'SkyDrome': {
29 | 'USDC': {
30 | 'USDT': '0xa631B2A2C3469aa1bF5dc49977207F378D16d7d8',
31 | }
32 | },
33 | 'SyncSwap': {
34 | 'ETH': {
35 | 'USDT': '0x78ea8E533c834049dE625e05F0B4DeFfe9DB5f6e',
36 | 'USDC': '0x814A23B053FD0f102AEEda0459215C2444799C70',
37 | },
38 | 'USDC': {
39 | 'ETH': '0x814A23B053FD0f102AEEda0459215C2444799C70',
40 | }
41 | },
42 | 'SpaceFi': {
43 | 'ETH': {
44 | 'USDC': '0x6905C59Be1a7Ea32d1F257E302401eC9a1401C52',
45 | },
46 | 'USDC': {
47 | 'USDT': '0x663864d52C38741001A73D270F4Da50005c647fA',
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/utils/data/types.py:
--------------------------------------------------------------------------------
1 | from typing import Callable
2 |
3 | from web3.contract import Contract
4 | from web3.types import TxParams
5 | from eth_typing import Address
6 | from web3 import Web3
7 |
8 |
9 | class Types:
10 | AmountOut = Callable[[str, Contract, int, str, Address, int, Web3], TxParams]
11 | SwapTransaction = Callable[[str, str, Contract, int, str, str, Address, int, Web3], TxParams]
12 | LiquidityTransaction = Callable[[str, Contract, int, str, Address, int, Web3], TxParams]
13 | LiquidityRemoveTransaction = Callable[[Web3, Contract, str, int, Address], TxParams]
14 | MintTransaction = Callable[[Web3, Contract, Address], TxParams]
15 | BridgeTransaction = Callable[[Contract, int, Web3], TxParams]
16 |
--------------------------------------------------------------------------------
/src/utils/errors/exceptions.py:
--------------------------------------------------------------------------------
1 | from typing import Any
2 |
3 | from config import SLIPPAGE
4 |
5 |
6 | class CustomError(Exception):
7 | def __init__(self, error_type: str, error_message: str) -> None:
8 | self.error = f'{error_type}: {error_message}'
9 | super().__init__(self.error)
10 |
11 |
12 | class ErrorHandler:
13 | def __init__(self, ex: Exception, *args: Any) -> None:
14 | self.__ex = ex
15 | self.__name = args[0]
16 |
17 | def handle(self) -> CustomError:
18 | if 'execution reverted' in str(self.__ex) and 'MainBridge' in str(self.__name):
19 | error_type = 'NotEnoughMoneyError'
20 | error_message = 'Not enough money for MainBridge transaction'
21 | elif 'execution reverted' in str(self.__ex) and 'PunkSwap' in str(self.__name):
22 | error_type = 'PriceImpactTooHigh'
23 | error_message = f"Can't execute transaction with slippage {SLIPPAGE * 100}%"
24 |
25 | else:
26 | error_type = 'Unknown Error'
27 | error_message = str(self.__ex)
28 |
29 | return CustomError(error_type=error_type, error_message=error_message)
30 |
--------------------------------------------------------------------------------
/src/utils/gas_checker.py:
--------------------------------------------------------------------------------
1 | from time import sleep
2 |
3 | from loguru import logger
4 | from web3 import Web3
5 |
6 | from config import MAX_GWEI
7 |
8 |
9 | def get_gas() -> int:
10 | try:
11 | w3 = Web3(Web3.HTTPProvider('https://rpc.ankr.com/eth'))
12 | gas_price = w3.eth.gas_price
13 | gwei = w3.from_wei(gas_price, 'gwei')
14 |
15 | return gwei
16 | except Exception as error:
17 | logger.error(f"Error while getting gas price: {error}")
18 |
19 |
20 | def wait_gas() -> None:
21 | while True:
22 | gas = get_gas()
23 |
24 | if gas > MAX_GWEI:
25 | logger.info(f'Current GWEI: {gas} > {MAX_GWEI}')
26 | sleep(60)
27 | else:
28 | break
29 |
--------------------------------------------------------------------------------
/src/utils/logger.py:
--------------------------------------------------------------------------------
1 | import loguru
2 |
3 |
4 | class Logger:
5 | def __init__(self, logger: loguru.logger) -> None:
6 | self.__logger = logger
7 |
8 | def info(self, __message: str, *args: object, **kwargs: object) -> None:
9 | self.__logger.info(f'{__message}', *args, **kwargs)
10 |
11 | def debug(self, __message: str, *args: object, **kwargs: object) -> None:
12 | self.__logger.debug(f'{__message}', *args, **kwargs)
13 |
14 | def error(self, __message: str, *args: object, **kwargs: object) -> None:
15 | self.__logger.error(f'{__message}', *args, **kwargs)
16 |
17 | def success(self, __message: str, *args: object, **kwargs: object) -> None:
18 | self.__logger.success(f'{__message}', *args, **kwargs)
19 |
20 | def warning(self, __message: str, *args: object, **kwargs: object) -> None:
21 | self.__logger.warning(f'{__message}', *args, **kwargs)
22 |
--------------------------------------------------------------------------------
/src/utils/user/account.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from time import sleep, time
3 |
4 | from web3.exceptions import TransactionNotFound
5 | from web3.types import TxParams
6 | from web3 import Web3
7 | from eth_typing import (
8 | Address,
9 | HexStr,
10 | )
11 |
12 | from src.utils.data.chains import SCROLL
13 | from src.utils.user.utils import Utils
14 |
15 |
16 | @dataclass
17 | class Wallet:
18 | address: Address
19 | private_key: str
20 |
21 |
22 | class Account(Utils):
23 | def __init__(self, private_key: str, rpc: str = SCROLL.rpc) -> None:
24 | self.web3 = Web3(Web3.HTTPProvider(rpc))
25 | self.account = self.web3.eth.account.from_key(private_key)
26 | self.account_address = self.account.address
27 |
28 | self.__wallet = Wallet(self.account_address, private_key)
29 |
30 | super().__init__()
31 |
32 | def get_wallet_balance(self, token: str, stable_address: str) -> float:
33 | if token.lower() != 'eth':
34 | contract = self.web3.eth.contract(address=Web3.to_checksum_address(stable_address),
35 | abi=self.load_abi('erc20'))
36 | balance = contract.functions.balanceOf(self.__wallet.address).call()
37 | else:
38 | balance = self.web3.eth.get_balance(self.__wallet.address)
39 |
40 | return balance
41 |
42 | def sign_transaction(self, tx: TxParams) -> HexStr:
43 | signed_tx = self.web3.eth.account.sign_transaction(tx, self.__wallet.private_key)
44 | raw_tx_hash = self.web3.eth.send_raw_transaction(signed_tx.rawTransaction)
45 | tx_hash = self.web3.to_hex(raw_tx_hash)
46 | return tx_hash
47 |
48 | def wait_until_tx_finished(self, tx_hash: HexStr, max_wait_time=180) -> bool:
49 | start_time = time()
50 | while True:
51 | try:
52 | receipts = self.web3.eth.get_transaction_receipt(tx_hash)
53 | status = receipts.get("status")
54 | if status == 1:
55 | self.logger.success(f"Transaction confirmed! {tx_hash}")
56 | return True
57 | elif status is None:
58 | sleep(0.3)
59 | else:
60 | self.logger.error(f"Transaction failed! {tx_hash}")
61 | return False
62 | except TransactionNotFound:
63 | if time() - start_time > max_wait_time:
64 | print(f'FAILED TX: {hash}')
65 | return False
66 | sleep(1)
67 |
--------------------------------------------------------------------------------
/src/utils/user/utils.py:
--------------------------------------------------------------------------------
1 | from typing import (
2 | Callable,
3 | Optional,
4 | Union,
5 | )
6 |
7 | from random import uniform
8 | from asyncio import sleep
9 | import json
10 |
11 | from web3.contract import Contract
12 | from web3.types import TxParams
13 | from web3 import Web3
14 | import loguru
15 |
16 | from eth_typing import (
17 | Address,
18 | HexStr,
19 | )
20 |
21 | from src.utils.logger import Logger
22 |
23 |
24 | class Utils:
25 | def __init__(self) -> None:
26 | self.logger = Logger(loguru.logger)
27 |
28 | def load_contract(self, address: str, web3: Web3, abi_name: str) -> Optional[Contract]:
29 | if address is None:
30 | return
31 |
32 | address = web3.to_checksum_address(address)
33 | return web3.eth.contract(address=address, abi=self.load_abi(abi_name))
34 |
35 | def get_decimals(self, contract_address: Contract, web3: Web3) -> int:
36 | contract = self.load_contract(contract_address, web3, 'erc20')
37 | decimals = contract.functions.decimals().call()
38 | return decimals
39 |
40 | async def approve_token(self, amount: float, private_key: str, from_token_address: str, spender: str,
41 | address_wallet: Address, web3: Web3) -> Optional[HexStr]:
42 | try:
43 | spender = web3.to_checksum_address(spender)
44 | contract = self.load_contract(from_token_address, web3, 'erc20')
45 | allowance_amount = self.check_allowance(web3, from_token_address, address_wallet, spender)
46 |
47 | if amount >= allowance_amount:
48 | self.logger.debug('🛠️ | Approving token...')
49 | tx = contract.functions.approve(
50 | spender,
51 | int(amount * 1.5)
52 | ).build_transaction({
53 | 'chainId': web3.eth.chain_id,
54 | 'from': address_wallet,
55 | 'nonce': web3.eth.get_transaction_count(address_wallet),
56 | "gasPrice": web3.eth.gas_price,
57 | })
58 |
59 | signed_tx = web3.eth.account.sign_transaction(tx, private_key=private_key)
60 | raw_tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
61 | tx_receipt = web3.eth.wait_for_transaction_receipt(raw_tx_hash)
62 | while tx_receipt is None:
63 | await sleep(1)
64 | tx_receipt = web3.eth.get_transaction_receipt(raw_tx_hash)
65 | tx_hash = web3.to_hex(raw_tx_hash)
66 | self.logger.success(f'✔️ | Token approved')
67 | await sleep(5)
68 | return tx_hash
69 |
70 | except Exception as ex:
71 | self.logger.error(f'Something went wrong | {ex}')
72 |
73 | def check_allowance(self, web3: Web3, from_token_address: str, address_wallet: Address, spender: str
74 | ) -> Optional[int]:
75 | try:
76 | contract = web3.eth.contract(address=web3.to_checksum_address(from_token_address),
77 | abi=self.load_abi('erc20'))
78 | amount_approved = contract.functions.allowance(address_wallet, spender).call()
79 | return amount_approved
80 |
81 | except Exception as ex:
82 | self.logger.error(f'Something went wrong | {ex}')
83 |
84 | def add_gas_price(self, web3: Web3) -> Optional[int]:
85 | try:
86 | gas_price = web3.eth.gas_price
87 | gas_price = int(gas_price * uniform(1.01, 1.02))
88 | return gas_price
89 | except Exception as ex:
90 | self.logger.error(f'Something went wrong | {ex}')
91 |
92 | def setup_decimals(self, from_token: str, from_token_address: str, web3: Web3
93 | ) -> Union[int, Callable[[str, Web3], int]]:
94 | if from_token.lower() == 'eth' or from_token.lower() == 'weth':
95 | return 18
96 | else:
97 | return self.get_decimals(from_token_address, web3)
98 |
99 | def create_amount(self, from_token: str, from_token_address: str, web3: Web3, amount: float) -> int:
100 | decimals = self.setup_decimals(from_token, from_token_address, web3)
101 | amount = int(amount * 10 ** decimals)
102 | return amount
103 |
104 | @staticmethod
105 | def create_liquidity_remove_amount(balance: int, remove_all: bool, removing_percentage: float) -> int:
106 | if remove_all is True:
107 | amount = balance
108 | else:
109 | amount = int(balance * removing_percentage)
110 |
111 | return amount
112 |
113 | @staticmethod
114 | def add_gas_limit(web3: Web3, tx: TxParams) -> int:
115 | tx['value'] = 0
116 | gas_limit = web3.eth.estimate_gas(tx)
117 | return gas_limit
118 |
119 | @staticmethod
120 | def load_abi(name: str) -> str:
121 | with open(f'./assets/abi/{name}.json') as f:
122 | abi: str = json.load(f)
123 | return abi
124 |
--------------------------------------------------------------------------------
/src/utils/wrappers/decorators.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | from asyncio import sleep
3 |
4 | from typing import (
5 | Callable,
6 | Optional,
7 | Any,
8 | )
9 |
10 | from loguru import logger
11 |
12 | from src.utils.errors.exceptions import ErrorHandler
13 | from src.utils.gas_checker import wait_gas
14 |
15 | from config import (
16 | PAUSE_BETWEEN_RETRIES,
17 | CHECK_GWEI,
18 | RETRIES,
19 | )
20 |
21 |
22 | def check_gas(func) -> Callable:
23 | def wrapper(*args, **kwargs) -> Callable:
24 | if CHECK_GWEI:
25 | wait_gas()
26 | return func(*args, **kwargs)
27 |
28 | return wrapper
29 |
30 |
31 | def retry(retries: int = RETRIES, delay: int = PAUSE_BETWEEN_RETRIES, backoff: float = 1.5) -> Callable:
32 | def decorator_retry(func: Callable) -> Callable:
33 | @wraps(func)
34 | async def wrapped(*args: Optional[Any], **kwargs) -> Optional[Callable]:
35 | for i in range(retries + 1):
36 | try:
37 | return await func(*args, **kwargs)
38 | except Exception as ex:
39 | if i == retries:
40 | logger.error(ErrorHandler(ex, *args).handle())
41 | else:
42 | await sleep(delay * (backoff ** i))
43 |
44 | return wrapped
45 |
46 | return decorator_retry
47 |
--------------------------------------------------------------------------------
/wallets.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nftscripts/scroll/c8cadeb3a914effba7a0fb3cb085a20a181aea16/wallets.txt
--------------------------------------------------------------------------------