梦入琼楼寒有月,行过石树冻无烟

📖 earlier posts 📖

Web3.0 Swap query

在上述的过程中我们了解到了各类型的方式,本文的作用主要是通过 BSC 链中的 Swap 方法来获取交易数据,并通过 Swap 方法所获取的交易 hash 来进行过滤。

在此之前,我们主要用到两个文件,一个是 helpers.py 来作为基础类,而另一个则为是 event_list.py 作为一个执行类,因为在大型项目中我们需要遵循项目的规范,因此我们会使用 class 来定义不同的类以及通过 def 定义方法。

我们需要做的是,helpers.py 中定义了一系列的基础类,先于 BSC 建立连接,同时定义 Redis 的连接方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
import json  
import time

import redis
from web3 import Web3

class RedisConnectionPoolSingleton(object):
_instance = None

def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = redis.ConnectionPool(max_connections=1000, host='127.0.0.1', port=6379, db=1)
return cls._instance

class web:
# 连接 Redis @staticmethod
def redis_client():
return redis.Redis(connection_pool=RedisConnectionPoolSingleton())

# 保存数据
@staticmethod
def save_task_result(param, task_key):
redis_con = redis.Redis(connection_pool=RedisConnectionPoolSingleton())
redis_con.rpush(task_key, json.dumps(param))
redis_con.close()

@staticmethod
def get_web():
bsc = "https://bsc-dataseed.binance.org/"
return Web3(Web3.HTTPProvider(bsc))

@staticmethod
def get_wbnb():
return '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'

@staticmethod
def get_busb():
return '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'

@staticmethod
def get_callback_key():
return 'laravel_database_task:callback'

#https://www.bscscan.com/tx/0xbbff0b938a1265265d36eddc2fc9274eadced1e19f43084211790b79ec7a36d8#eventlog
@staticmethod
def get_swap():
return '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'

@staticmethod
def get_tran():
return '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'

@staticmethod
def get_unique_md5(unique):
import hashlib
return hashlib.md5(unique.encode(encoding='UTF-8')).hexdigest()

@staticmethod
def set_task_implement_status(unique):
key = 'tesk:implement'
unique = web.get_unique_md5(unique)
redis_client = web.redis_client()
if redis_client.sismember(key,unique):
return False
redis_client.sadd(key,unique)
return True

@staticmethod
def analyse_receipt(txhash):
global returnjson
web3 = web.get_web()
receipt = web3.eth.getTransactionReceipt(txhash)
logs = receipt['logs']
returnJson = {}
common = {}
common['0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'] = 'BNB'
common['0xe9e7cea3dedca5984780bafc599bd69add087d56'] = 'BUSD'
temAddress = ''
for log in logs:
if log['topics'][0].hex() == '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef':
if temAddress != None and temAddress != log['address']:
returnJson['isSwap'] = 1

temAddress = log['address']
kk = common.get(log['address'])
if kk == None:
token = log['address']
returnJson['token'] = token
else:
pairToken = log['address']
returnJson['pairToken'] = pairToken
return returnJson

# https://www.bscscan.com/token/
@staticmethod
def get_all_detail(web3, token):
token = web3.toChecksumAddress(token)
contract_abi = '[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint256","name":"votes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCurrentVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPriorVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]'

# <web3._utils.datatypes.Contract object at 0x0000024E7CC6C358>
token_contract = web3.eth.contract(address=token, abi=contract_abi)
print('token_contract:', token_contract)

# 获取 token 小数 > 18 token_decimals = token_contract.functions.decimals().call()
print('token_decimals:', token_decimals)

# 获取合约中所存储的 token 数量 > 18000000.0 token_total_supply = token_contract.functions.totalSupply().call() / (10 ** token_decimals)
print('token_total_supply:', token_total_supply)

# 获取 token 的符号 > XMETA token_symbol = token_contract.functions.symbol().call()
print('token_symbol:', token_symbol)

# 获取 token 的名称 > token_name = token_contract.functions.name().call()
print('token_name:',token_name)

# 获取 token 的价格
burn_balance = web.get_token_balance(token_contract, '0x000000000000000000000000000000000000dEaD')
print('burn_balance:',burn_balance)

# 流动池数据获取
price = web.getPoolDetail(token)
print('price:',price)

# 发行 token 的数量 - 转发到黑洞中的数量
total_liquidity = token_total_supply - burn_balance
print('total_liquidity:', total_liquidity)

# 获取连接池信息
total_balance = round(total_liquidity * price.get('price', 1))
print('total_balance:', total_balance)
return_str = {
'token': token,

# token 位数
'token_decimals': token_decimals,
# token 总数
'token_total_supply': str(token_total_supply),
# token 符号
'token_symbol': token_symbol,
# token 名称
'token_name': token_name,
# 黑洞地址所持有的金额
'burn_balance': burn_balance,
# token 的总余额
'total_balance': str(total_balance),
# 价格
'price': '{:.16f}'.format(price['price']),
# 当前的价格
'coin': price['coin'], #池子类型
# 连接池地址
'pair_address': price['pairAddress'], # 池子地址
# 池子(BNB,BUSD)金额
'pair_balance': price['pairBalance'],
# 池子 token 数量
'pair_token_balance': price['pairTokenBalance'],
}
# 价格,总供应量,名称,token,流动池地址,流动池大小,市值,黑洞持有量
print('return_str:', return_str)
print('》》》——————————————————————————————————————————————————————————————————————————————————————————')
return return_str

# 获取 token 价格
@staticmethod
def get_token_balance(token_contract, address):
# 通过 ERC20 decimals 使得可以发送小数 > token_decimals = token_contract.functions.decimals().call()
print('token_decimals:', token_decimals)

# 返回账户所有者中的所有 NFC 数量 > token_balance = token_contract.functions.balanceOf(address).call()
print('token_balance:',token_balance)

return round(token_balance / (10 ** token_decimals), 16)

# WBNB 与 BUSD @staticmethod
def wbnbtoBusd(amount):
web3 = web.get_web()
busd = web.get_busb()
wbnb = web.get_wbnb()
panRouterContractAddress = '0x10ED43C718714eb63d5aA57B78B54704E256024E'
panabi = '[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]'
contract = web3.eth.contract(address=panRouterContractAddress, abi=panabi)
amount = web3.toWei(amount, 'ether')
price = contract.functions.getAmountsOut(amount, [wbnb, busd]).call()
return round(price[1] / (10 ** 18), 16)

# 获取流动池详情
@staticmethod
def getPoolDetail(token):
web3 = web.get_web()
wbnb = web3.toChecksumAddress('0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c')
busd = web3.toChecksumAddress('0xe9e7cea3dedca5984780bafc599bd69add087d56')

wbnbAbi = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]'
wbnbContract = web3.eth.contract(address=wbnb, abi=wbnbAbi)

factoryAddress = web3.toChecksumAddress('0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73')
factoryabi = '[{"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pair","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"PairCreated","type":"event"},{"constant":true,"inputs":[],"name":"INIT_CODE_PAIR_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allPairs","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allPairsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"createPair","outputs":[{"internalType":"address","name":"pair","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"feeToSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"setFeeTo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_feeToSetter","type":"address"}],"name":"setFeeToSetter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]'
factoryContract = web3.eth.contract(address=factoryAddress, abi=factoryabi)

busdAbi = '[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"_decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]'
busdContract = web3.eth.contract(address=busd, abi=busdAbi)
token = web3.toChecksumAddress(token)

contractAbi = '[{"constant":true,"inputs":[],"name":"mintingFinished","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"cap","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"finishMinting","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"burner","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"MintFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]'
tokenContract = web3.eth.contract(address=token, abi=contractAbi)

t = time.time()
pairAddress = factoryContract.functions.getPair(wbnb, token).call()
print('pairAddress:',pairAddress)

busdPair = factoryContract.functions.getPair(busd, token).call()
print('busdPair:',busdPair)

pair_token_balance = web.get_token_balance(tokenContract, pairAddress)
print('pair_token_balance:',pair_token_balance)

pair_balance = web.get_token_balance(wbnbContract, pairAddress)
print('pair_balance:',pair_balance)

t = time.time()
returnStr = {}
if pairAddress != '0x0000000000000000000000000000000000000000' and busdPair != '0x0000000000000000000000000000000000000000' and pair_token_balance != 0 and pair_balance != 0:
busdpair_balance = web.get_token_balance(busdContract, busdPair)
pair_balance1 = web.wbnbtoBusd(pair_balance)
if busdpair_balance > pair_balance1:
busdpair_token_balance = web.get_token_balance(tokenContract, busdPair)
price = round(busdpair_balance / busdpair_token_balance, 16)
returnStr['coin'] = busd
returnStr['pairAddress'] = busdPair
returnStr['pairBalance'] = busdpair_balance
returnStr['pairTokenBalance'] = busdpair_token_balance
returnStr['price'] = price
else:
price = round(pair_balance / pair_token_balance, 16)
returnStr['coin'] = wbnb
returnStr['pairAddress'] = pairAddress
returnStr['pairBalance'] = pair_balance
returnStr['pairTokenBalance'] = pair_token_balance
returnStr['price'] = web.wbnbtoBusd(price)
elif pairAddress != '0x0000000000000000000000000000000000000000' and pair_token_balance != 0 and pair_balance != 0:
price = round(pair_balance / pair_token_balance, 16)
returnStr['coin'] = wbnb
returnStr['pairAddress'] = pairAddress
returnStr['pairBalance'] = pair_balance
returnStr['pairTokenBalance'] = pair_token_balance
returnStr['price'] = web.wbnbtoBusd(price)
elif busdPair != '0x0000000000000000000000000000000000000000':
busdpair_token_balance = web.get_token_balance(tokenContract, busdPair)
busdpair_balance = web.get_token_balance(busdContract, busdPair)
price = round(busdpair_balance / busdpair_token_balance, 16)
returnStr['coin'] = busd
returnStr['pairAddress'] = busdPair
returnStr['pairBalance'] = busdpair_balance
returnStr['pairTokenBalance'] = busdpair_token_balance
returnStr['price'] = price
return returnStr

在上述的 code 中,我们大致可分为 基础类、查询类、过滤类等三种。

base

基础类主要是 RedisConnectionPoolSingleton 下的 _instance_ 来创建的 Redis 方法,通过 __new__ 方法来进行连接,之后返回给 _instance 变量。

同时在 web 方法中,通过 redis_client() 方法来连接 redis,同时定义一个保存数据的方法 save_task_result 将之后 event_list.py 之后所过滤掉的数据通过 json.dumps 的方法来进行存储。

1
```json.dumps``` 使用此转换表将obj序列化为JSON格式的str。参数的含义与dump()中的相同。

Swap Exact

在 Etherscan 和 Bcanscan 中,作为区块链开发,主要关注的点是交易数据中的 Tokens Transferred 参数项来理解本次交易过程是干什么的,通常在 Bcanscan 的 Input Data 内,都是已经帮助我们解析完成的,在 web 3.0 中,主要通过 Contranct Factions 即 “合约工厂” 来进行创建一个合约对象。

swapExactTokensForTokens 以Token为基准互换为 Tokens


Binance Transaction Hash (Txhash) Details | BscScan 这一份交易中,特别是 Input DataTokens Transferred: 栏的信息内,这一交易主要是通过 0xf… 钱包将≈154.15$的Binace-Pag(在池子中可能名字为 ESC-US) 放入到 PancakeSwap 转换池中。

然后池子将 ≈154.15 的 BSC-US 兑换 17.8637… FistToken 发送到 0xf87… 钱包内。可以看出这一交易主要是将 BSC-US 转换为 FIST。

对于这个方法我们可以通过直译的方式来进行理解,“为 Tokens 转换确切的代币”,结合 Tokens Transferred 中的数据再配合中文直译来进行理解。之后在 web3.0 中,主要通过 eth.contrace 来解析合约工厂:

1
2
3
4
5
@staticmethod
def get_router_contract(web3):
pan_router_contract_address = ''
router_abi = ['']
return web3.eth.contrace(address=pan_router_contract_address, abi=router_abi)
1
为了使整体项目目录和 Code 更加美观,通过 flask 框架,我们可以将上述基础类方法写在 ```Helper.py``` 内,之后我们在 ```main.py``` 启动类引用即可。
方法中包含的参数主要有六个参数,分别体现了该合约方法的主要用处:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

| Id | Name | Info | type |
| --- | --- | --- | --- |
| 1 | amountin | 金额,要发送的 token 数量 | unint |
| 2 | amountOutMin | 最小金额,为了使交易不被逆转,所必须受到的最小输出代币量 | unint |
| 3 | path | 一个目标地址池(流动池必须存在,且拥有流动性, ```path.length > 2```) | address[]calldata |
| 4 | to | token 的接收者 | address |
| 5 | deadline | Unix 时间戳(在此之后将会恢复) | unint |

我们可以通过一个具体的项目是示例来结合官方文档以及 web3.0py 中来进行更深一步的了解:

```python
pancakeswap2_txn = router_contract.functions.swapExactTokensForTokens(
buy_value,
slippage, # set to 0, or specify minimum amount of tokeny you want to receive - consider decimals!!!
[value_type_address, pair_type_address, tokenToBuy],
sender_address,
(int(time.time()) + 10000)
).buildTransaction({
'from': sender_address,
'gas': int(gas),
'gasPrice': web3.toWei(str(gas_price), 'gwei'),
'nonce': nonce,
})

通过上述的 code 中我们可以看到基本上就是非常符合 swapExactTokensForTokens
所传入的参数,而之后的 .buildTransaction 方法是交易交易,指定合约调用并构建事务字典,包含了诸如 from 以及 gasnonce 等参数。

但在此之前我们可以知道 WETH 是 Address 的方法组,更多的我们可以参考官方文档给出的解释。

之后我们在 15581850 块内其中一个交易信息中,在其 Interacted With(To) 栏中,进入到该合约页面中,可以在其 Contract 内查看合约的具体信息以及合约的 Code 等。

同样的我们也可以在 Contract Source Code (Solidity) 栏中查看合约的源代码,具体的与 uniswap 都相差无几。

swapExactETHForTokens 以 ETH 为基准将 ETH 互换为 Tokens

通过 ETH 交换 token,在 Bsccan 中,由于套的 Ethscan 所以通过此方法交易的类型,也会在交易详情页中的 Value 内进行标注通过 BNB 交易的份额,例如 Binance Transaction Hash (Txhash) Details | BscScan中。

通过此方法进行交易,将会附带一个 payable 参数,用于可能、可以、或必须支付的费用,在其他非 Eth 交易的数据中,则不会将交易的数额写入到 Value 栏内。该方法的第一个参数必须是 WBNB 也就是 WBNB 的地址等,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
if value_type_address == 'BNB' and pair_type_address == wbnb:  
pancakeswap2_txn = router_contract.functions.swapExactETHForTokens(
0, # set to 0, or specify minimum amount of tokeny you want to receive - consider decimals!!!
[wbnb, tokenToBuy],
sender_address,
(int(time.time()) + 10000)
).buildTransaction({
'from': sender_address,
'value': buy_value, # This is the Token(BNB) amount you want to Swap from
'gas': int(gas),
'gasPrice': web3.toWei('12', 'gwei'),
'nonce': nonce,
})

在上述的 code 中,与 swapExactTokensForTokens 的区别之处在于 payable ,这个在 web3.0 的概述中,我们可以得知,payable 就是 value 只有通过 WBNB 进行交易的时候。

1
对于其他的方法,只要涉及 ```payable``` 变量,那么就表明这个东西是需要进行 BNB 交易份额的。

在此之前,我们需要了解下一个交易时的概念,就是滑点(Slippage) 也就是在交易的过程中来描述交易在等待时可能发生改变的属于,当交易被提交到 ETH 时,他们的执行顺序时根据 gas 数量来决定的(提供的 gas 费用越高,所执行的速度也就越快。在这其中他所最终交易的价格环境也会发生变化,因为加密货币的市值也是不断变化的)

滑点的容忍度他建立了一个用户可以所接受的超出价格影响的变化幅度,只要价格在滑点的范围内,那么交易就会被执行。

swapETHForExactTokens 以 Tokens 为基准来通过 ETH 来进行换取

我们可以看到同样是互换的交易类型,Binance Transaction Hash (Txhash) Details | BscScan 的交易类型和 swapExactTokensForTokens 的区别在于,之处可以看下方的图片介绍:

从上图可以得知,两个转换方法的不同指出在于,买入的方式不同,后者是通过 BNB 货币价值等价于 tokens 来进行买入 Tokens,而前者则是通过买入 tokens 数量来支付 BNB,一般来说 swapETHForExactTokens 会更加精准些许。

需要注意的是,按照 uniswap 的 function 命名规则,通常是 Exact 跟在谁的后面,那么就精准谁的数据信息,比如 Exacttoken 后面,那么他的数据就较为精准,反而毅然。

swapExactTokensForETH 准确地将 token 交换出 ETH

准确的将 token 交换出的 ETH,用于将一个接近整数的 token 互换为 ETH,并进行交易。

你可以通过 Binance Transaction Hash (Txhash) Details | BscScan 来查看真实的交易数据,之后通过 Web3 来进行 Swap 交易的进行。

Etherscan and Bscscan

EtherscanBscscan 的区别就是以太坊链和币安链,由于两者在其自己的链浏览器中都相差不大,所以我们可以通过任意一个链的学习来了解两个链浏览器的功能和开发中需要的几个参数点。

在其首页中 Latest Blocks -> #Block 中,我们可以从其交易数据中来了解到链的整个交易过程和所涉及的知识点等信息,通过这些信息可以让我们之后在开发中进行利用并熟练的操作。

在之前的 web3.0 中我们通过 Provider 所提供的方法来进行获取块中的数据信息,那么我们可以在 Etherscan \ Bscscan 中来看到他们链官方是如何使用这些信息且展示的。

Block view

区块是一个核心的概念,我们可以理解为是将其分类帐中的页面,区块包含了交易数据和前一个区块的哈希值,从而确保区块链网络中的不可变性和安全性,因此一个完整的 Block 中,他通常包含了下列数据:

Id Name Info
1 Block Height 区块的高度,通常被称之为区块编号,表示该区块在链中的位置
2 Timestamp 时间戳
3 Transactions 区块中的交易数量,以及合约内部交易数据(指从合约执行中所创建并进行交易的以太币数量)
4 Mined by 成功开采这个区块的矿工
5 Block Rewad 矿机因将该块包含在区块链中而获得的总块奖励。奖励明细(静态块奖励、总交易费、扣除烧费、叔叔包含奖励)也会显示出来。
6 Uncles Reward 奖励采矿者在观察到的区块中开采未开采的区块。
7 Difficulty 开采一个新区块所需的工作量。难度根据区块链上的总哈希幂挖掘进行调整。
8 Total Difficultty 到目前为止的区块挖掘总难度
9 Size 块的大小,他由区块的 GAS 限制所决定
10 Gas Used 块中所使用的总 GAS,还包括使用 gas 百分百以及超过 gas 目标使用的 gas 百分比。
11 Gas Limit 区块中的总 gas 限制
12 Base Fee Per Gas 包含在块中的 tx 所需的最小 gasUsed 乘数
13 Burnt Fees 代表 tx 费用中被烧掉的部分:baseFeePerGas * gasUsed
14 Burnt Data 矿工可以包含在区块中的任何数据
15 Hash 当前区块的区块头哈希
16 Parent Hash 生成此块的块哈希,通常称之为其夫块
17 Sha3Uncle 以太坊 Javascript RLP 编码空字符串的机制
18 StateRoot 状态树的根
19 Nonce 区块随机量数是在挖掘过程中用于展示区块工作量证明的值

这在以太坊的官方知识库中均有记录,我们可以翻阅其官方的知识库来查阅有关以太坊链的相关信息和资料 Exploring the Block Details (etherscan.com)。无论是在 Etherscan 还是之前我们通过 web3.0 来请求块数据所返回的信息内,均都涉及一个概念类的东西,即 GAS :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
'author': '0xad5C1768e5974C231b2148169da064e61910f31a',
'difficulty': 735512610763,
'extraData': '0x476574682f76312e302e302f6c696e75782f676f312e342e32',
'gasLimit': 5000,
'gasUsed': 0,
'hash': '0x767c2bfb3bdee3f78676c1285cd757bcd5d8c272cef2eb30d9733800a78c0b6d',
'logsBloom': '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'miner': '0xad5c1768e5974c231b2148169da064e61910f31a',
'mixHash': '0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
'nonce': '0x549f882c5f356f85',
'number': 12345,
'parentHash': '0x4b3c1d7e65a507b62734feca1ee9f27a5379e318bd52ae62de7ba67dbeac66a3',
'receiptsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
'sealFields': ['0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
'0x549f882c5f356f85'],
'sha3Uncles': '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
'size': 539,
'stateRoot': '0xca495e22ed6b88c61714d129dbc8c94f5bf966ac581c09a57c0a72d0e55e7286',
'timestamp': 1438367030,
'totalDifficulty': 3862140487204603,
'transactions': [],
'transactionsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
'uncles': [],
}

由于以太坊网络是一个分散的区块链,没有单一的实体或机构监管或其运营,因此建立了一个机制来避免网络堵塞或者垃圾邮件的交易信息,这种机制的主要原理是向交易发送者收取一笔称之为 GAS 费的小额费用 ETH 将使用这类资金奖励网络上验证交易的矿工。

1
这笔费用将会以 ETH 形式出现,也应用在以太坊网络中,从而促进价值来进行转移,采矿指出和智能合约的执行,GAS 的工作方式主要类似于汽油费的方式,类似于**车辆//燃料的工作方式,为了从 A~B 点,车辆所加满足够的汽油** 因此如果要让 ETH 交易成功,发送方必须提供足够的 ETH 来支付 GAS 费用。

GAS 的交易是从交易方地址剩余的 ETH 余额中所扣除的,而不是从发送的 ETH 或代币数量中扣除的,他还会再单个事件中自动与交易方进行扣除,更多关于 GAS 的信息,比如如何计算或设置 GAS 费用,我们可以通过 什么是汽油费 (etherscan.com) 来进行详细查看。

Transaction

交易数据(Transaction) 这是在 Etherscan 中所公开的,可与在 Latest Transaction 中来进行查看,Latest Transactions -> TX 在这你可以看到一个钱包到另一个钱包中的 ETH 余额的流动。

之后我们点进支付方的钱包地址可以看到详细的交易数据,Ethereum Transaction Hash (Txhash) Details | Etherscan 他主要包含了如下信息:

Id Name Info
1 Transaction Hash 事务散列,每单执行事务时所生成的唯一标识符称之为 TxnHash可用于追踪事务的状态
2 Status 当前的交易数据,分为成功和失败,分别对应着交易成功和交易未成功(交易金额将在 gas 后退还 )
3 Block 记录此事务块的编号
4 Timestamp 记录交易后的持续时间,以及记录交易的确切日期和时间。
5 From 发钱人地址
6 To 收款人地址
7 Value 本次交易的金额
8 Transaction Fee 本次交易所产生的费用或实际成本(Txn x GAS),无论交易是否成功 gas 都会是支付给矿工的
9 Gas Price 这一交易中所使用的最大 gas 单位
10 Gas Limit & Usage by Txn 此次交易使用 gas 的确切单位
11 Gas Price Gwei 为此交易所指定的天然气单位成本
12 Outher 与该事务相关的一些其他数据
13 Input Data 此事务包含其他数据,通常包含合约交互的一部分或者发给收钱人的信息
14 Private Note 记录交易中的私人注释,只有登入 etherscan 中才可查看

对于上述 14 中信息的注解,我们可以查阅 Etherscan 中的官方文档来解答我们的问题,通过官方文档中可以了解到很多信息: What is a Transaction Hash (etherscan.com)

在此之前,我们还需要先了解下流动池与AMM自动做市机制,之后在通过 BscScan 看块中方法为 Swap Exact Token... 的数据。

根据上图的解释,我们可以大致看清楚关于Swap Exact Token... 的流动池的交易数据,在区块链中是不存在 买和卖 的概念的,只有交易,Value 是交易中的BNB数量,可能为空也有可能有值。

这些都需要通过 Tokens Transferred 中来进行整理顺序,理清逻辑关系才可以理解到整个交易数据链的意思。

还需要主要的是,在上述页面中的 Gas Price 即本次交易的 gas 费用为 0.000000005 BNB 也就是 5 gwei,而 “gwei” 是什么我们可以通过 web3.0 官方文档中的解释来进行对照。

Web3.0 概述

Web 3.0 又被称之为 Web3,是 WWW 发展的一个概念,主要是基于区块链的去中心化,和非同质化代币(Non-Fungible Token) 有关,是一种区块两数字账本上的数据单位。

这个概念于 2014年由以太坊联合创始人 Gavin Wood 提出,并在 2021 年受到大量的科技公司和加密货币爱好者所关注。

1
Web3.0 不仅仅只包含了区块链的去中心化,他拥有多个含义,用来概括互联网发展的过程中出现不同的特征,包括泛型数据库、跨浏览器、人工智能技术应用等

Provider

Providers(提供者) 通过接受 JSON-PRC 请求并返回响应,通常是基于 HTTP 或 IPC 套接字的服务器提交请求来达成目。

目前最常见的连接结点的方式有很多,可以根据自身的需求以及项目的应用场景进行搭配和选择:

  1. IPC(uses local filesystem:fastest and most secure, 使用本地文件系统,最快和最安全)
  2. Websockets(works remotely, faster than HTTP, 远程工作,比 HTTP 块许多)
  3. HTTP(more nodes support it, 更多的节点都支持)

当我们可以选择于节点相同的计算机中运行 web3.py 那么我们就采用 IPC 方式,但我们要连接另一台计算机上的节点,那么可以使用 Websockets,又或者我们的节点不支持 websocket,那么就用 HTTP。

之后,我们就可以通过 web3 来配置我们的 Provider 也就是供应商或是内容提供者:

1
如果你是 Linux 开发环境或者通过 WSL 虚拟映射到 Windows 进行开发的,那么我们还需要通过 pip 安装 ```setuptools``` 才可使用 ```web3``` 的库 
1
2
3
4
from web3 import Web3  

w3 = Web3(Web3.HTTPProvider('URI'))
res = w3.isConnected()

之后,我们可以通过 w3.isConnected() 来初始化连接,以此来获取一个最新的块:

1
2
3
4
5
6
7
from web3 import Web3  

w3 = Web3(Web3.HTTPProvider('URI'))
res = w3.isConnected()

latest_block = w3.eth.get_block('latest')
print(latest_block)

那么根据 w3.eth.get_block 来获取一个最新的块,也就是说我们已经连接到 ETH 的全球网络中,可以获取很多的信息:

在此,每一个块都有它与之前所产生块的引用,通常被 web3 称之为 “和”,它主要由哈希值进行表明,包含在 parentHash 键值内。

需要注意的是区块链本质上是一个链表,每一个快都有对前一个块的引用,这种数据结构在点对点网络中很是新颖,使得其他人都会知道,当向朋友汇款时,我们需要将交易光波到网络中,然后其他人就会知道,这就是类似于这个概念。

查找块

块可以通过 API 或者其他编号散列进行查看,一个块的哈希是十六进制表示的形式,块是可以通过 hash 或者 number 来进行查找的,同样的我们也可以实用 latest 来获取最新的快。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
'author': '0xad5C1768e5974C231b2148169da064e61910f31a',
'difficulty': 735512610763,
'extraData': '0x476574682f76312e302e302f6c696e75782f676f312e342e32',
'gasLimit': 5000,
'gasUsed': 0,
'hash': '0x767c2bfb3bdee3f78676c1285cd757bcd5d8c272cef2eb30d9733800a78c0b6d',
'logsBloom': '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'miner': '0xad5c1768e5974c231b2148169da064e61910f31a',
'mixHash': '0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
'nonce': '0x549f882c5f356f85',
'number': 12345,
'parentHash': '0x4b3c1d7e65a507b62734feca1ee9f27a5379e318bd52ae62de7ba67dbeac66a3',
'receiptsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
'sealFields': ['0x31d9ec7e3855aeba37fd92aa1639845e70b360a60f77f12eff530429ef8cfcba',
'0x549f882c5f356f85'],
'sha3Uncles': '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
'size': 539,
'stateRoot': '0xca495e22ed6b88c61714d129dbc8c94f5bf966ac581c09a57c0a72d0e55e7286',
'timestamp': 1438367030,
'totalDifficulty': 3862140487204603,
'transactions': [],
'transactionsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
'uncles': [],
}

latest 类似的还有 eth.bllock_number 来获取最新的块号,之后通过 eth.get_block 来获取详细信息。

查询余额

在上述中我们通过 eth.get_block 来获取块的详细信息中,所返回的 miner 内包含了钱包的数据,之后我们可以通过 eth.get_balance 来获取钱包账号,之后我们还需要i通过实用 Web3.fromWei 来进行转换:

1
2
3
4
5
6
7
8
9
from web3 import Web3  

w3 = Web3(Web3.HTTPProvider('URI'))
res = w3.isConnected()

latest_block = w3.eth.get_balance('0x3EcEf08D0e2DaD803847E052249bb4F8bFf2D5bB')
print(latest_block)

print(Web3.fromWei(2922220972276471416291, 'ether'))

或者通过其他方法一下子直接进行过滤,以此来查看数据的帐号余额等信息来进行输出:

1
2
3
4
5
check_sun = w3.toChecksumAddress('0x3EcEf08D0e2DaD803847E052249bb4F8bFf2D5bB')  
balance = w3.eth.get_balance(check_sun)

ether_value = w3.fromWei(balance,"ether")
print(ether_value)

之后通过 Web.fromWei 来对获取的数据进行转译为 ether 的货币面值,来进行转化,针对货币的面值,可以通过 Examples — Web3.py 5.28.0 documentation (web3py.readthedocs.io) 来进行查看 。

交易

在交易方面,主要通过 send_transcation()send_raw_transaction() 还有合约以及中间件等,以此来应对多种不同的场景,通过指定或者类似的场景来来选择不同的交易方法:

  1. 假设我们只需要将以太币从一个账号中发送到另一个账号中,那么使用 send_transaction() 方法就可以实现需求。

  2. 再或者我们需要在其他地方签署交易,需要使用硬件钱包和其他提供商等进行广播交易和更大灵活性更高的高级用例,可以选择 send_raw_transaction()

1
2
3
4
5
6
7
8
web3.eth.send_transaction({
'to': '0xd3CdA913deB6f67967B99D67aCDFa1712C293601',
'from': web3.eth.coinbase,
'value': 12345,
'gas': 21000,
'maxFeePerGas': web3.toWei(250, 'gwei'),
'maxPriorityFeePerGas': web3.toWei(2, 'gwei'),
})

在上述的 code 中,主要是将以太坊发送到零一个账号中,那么使用的就是 send_transaction 方法来进行构造,他的主要参数如下:

同时,我们还可以通过 web3.eth.get_transaction 来查找交易记录以及 get_transaction_receipt 查找收据,具体的可以查阅官方文档 示例 — Web3.py 5.28.0 文档 (web3py.readthedocs.io)

过滤器

过滤器的实现主要可以通过 web3.eth.Eth.filter() 方法来设置一个过滤器,通过相应的参数来组合一个新的过滤器,因此我们可以通过 eth>filter('latest') 来获取新的块信息,16 进制的消息头:

1
2
3
4
5
6
7
8
from web3.auto import Web3  

w3 = Web3(Web3.HTTPProvider('URI'))

res = w3.isConnected()

new_block_filter = w3.eth.filter('latest')
print(new_block_filter.get_new_entries())

此外,Web3 还为我们提供了新的过滤器,如 fo;ter.filter_id 来获取并创建一个 RPC 方法打来返回新的筛选器,或者检索新的条目,可以阅览筛选 — Web3.py 5.28.0 文档 (web3py.readthedocs.io)

合约

智能合约是一种自动执行的合同,由买卖双方之间的协议条款直接写入代码行中,分散在区块链网络中,通过代码控制执行,他也允许在不同的匿名方之间执行可信交易和协议,无需中央机构进行管理,符合去中心化的理论和趋势。

智能合约也是一种计算机程序或交易程序,目的是减少可信中介人的需求,仲裁和执行成本,用来减少恶意的异常,他只是区块链中上存储的程序,在满足一定条件的时候执行,通常用于自动执行协议,以便所有参与者都可以立即确定结果,而不需要中介人的参与来减少时间损失。

合约可以在满足条件的时候触发下一个操作并且开发者通过 ABI 来进行接口的调用和操作,在目前,智能合约的概念已经被运用到供应商关系的信任和国际贸易,使得交易双方更快、更高效。

流动池与AMM 自动做市机制

在了解流动池与AMM自动做市机制之前,我们需要了解下 DeFi 即去中心化金融(Decentralized finance),它是一种新兴的金融技术,通常类似于加密货币所使用的分布式账本(钱包),他主要的方便之处在于:

  1. 方便了其他金融公司所收取的费用
  2. 余额存放在安全的数字钱包中
  3. 可以在任何由网络连接的地方使用
  4. 可以在在分钟或几秒钟内转移你的资金。

DeFi 主要使用加密货币进行交易,而传统的 CeFi (集中财务,Centralized Finance) 中,你的钱归银行持有,他们的目的主要就是为了赚钱,以此完成一整个金融系统的流动,在一小部分的银行厂商内,你在转账时都会进行一定的收费。

而其它的金融服务也都需要收费,甚至你向银行申请贷款,也都需要几天甚至是几月来进行批准,这可能会耽误你的时间。

而去中心化金融他主要是创建于区块链上的金融模式,且不依赖于卷商、交易所或银行等金融交易机构所提供的金融工具,主要利用区块链上的智能合约,以此来进行交易活动。

1
DeFi 平台允许人们向他人借出或借入资金,交易加密货币,并在类似于储蓄账户中获取利息

流动资金池

Liquidity Pools,即流动资金池,使得用户能够在分散的交易所(DEX)和其他的 DeFi 平台上买卖加密货币。在 DeFi 中,交易者为分散式交易所(DEX,Decentralized exchange) 提供流动性。

1
DEX 是一种加密货币交易所,允许直接的点对点加密货币在线交易,无需中介。

流动池是一种机制,通过该机制用户可以将其资产汇聚到 DEX 的智能合约中,为交易者在交易货币之间提供资产的流动性。

1
2
3
4
5
6
7
8
9
智能合约是区块链中的基础技术,同时也是以太坊网络中的关键要素,智能合约是自动执行的一组 Code,然后在区块链上进行验证。可以将智能合约理解成传统意义上的合同,同样是多方之间的协议,其中以方向另一方提供有价值的东西,而且交易双方要被智能合约所约束。

他与传统的交易来进行对比,不同之处在于,智能合约可以自动执行协议条款中的 Code,然后 Code 会发送到区块链上的地址,由该区块的共识机制进行验证,一旦交易包含在此区块中,那么就会执行智能合约且发生不可挽回的操作。

在智能合约中,消除了传统 CeFi 中的中介以及合同的执行需求,简化了合同的谈判过程,主要通过 Code 来定义交易的机制,从而成为条款的仲裁者。

但智能合约也有缺点,就是如果智能合约中的 Code 出现或存在错误,则会使得智能合约无效,且不可更改。因为智能合约是无信任、自主、分散且透明的,一旦部署他就是不可逆以及不可修改的存在。

**一个合约就是一个交易货币**,一个资金流动池中包含了多了加密货币,在资金池中我们可以指定的转换币的类型。

流动资金池的主要协议是 Bancor ,但随着 Uniswap 的普及使得这一概念引起了更多的关注,在详细了解流动池之前,我们可以先了解下 Uniswap。

Uniswap 是一个领先的分散式加密交易所,完全的去中心化,这意味着他不是由单个实体所运营,而是采用一种相对于新颖的交易模型,称之为流动性协议

Uniswap

Uniswap 系统就是一个自动化的流动性协议,通过常数乘积公式进行驱动这也是 Uniswap 所使用的自动做市算法 词汇表|优斯瓦普 (uniswap.org) 在 Uniswap 中的智能合约内,都管理着由一个由两个 ERC-20 合约所储备组成的流动性机制。

1
ERC20 tokens 是一个合约标准,也是 token 的标准接口,允许智能合约为 token 实现标准的 API 该标准提供了转移 token 的基本功能并允许 token 获得批准,使得可以在链上第三方应用。

任何人都可以成为流动池与流动池提供者 (Liquidity provider,LP),其方法主要是存入每个底层 token 的等价值,以换取流动池 token。

Pool

Uniswap 的独特之处在于,他不会使用订单薄来推到资产的价格,也不会匹配 token 的买家和卖家,是一个完全去中心化的平台和交易流程。

每个 Uniwap 流动池都是一堆 ERC20 合约所交易的场所,起初在创建时每个 token 都为 0,第一个 LP 是设定流动池初始加价格。

无论何时何地将流动性存入到流动池中,都会生成一流动性 token 并将其发送到提供者的地址,流动池中的流动性比列决定了提供者收到的流动性 token(Liquidity tokens)

1
Liquidity tokens 本身就是可以交易的资产,LP(Liquidity providers,流动提供者)可以出售、转让或者以其他方式其流动性的 token。 

为了获取相关的流动性,加上其他费用,LP 必须烧掉自己的 Liquidity Tokens 以任何他们所认为的合适方式。

AMM

自动化做市商(American Metal Market) 可以理解为一种机器人,可以让买卖双方的资产进行报价。而他主要是一种去中心化的交易平台(DEX) 合约,通过数学公式对资产等进行定价(主要通过算法进行完成),而不是传统的订单薄。

1
订单薄是一个按照价格排序的当前资产目前开放的买卖订单列表

AMM 的定价公式会随着不同的合约进行变化,这类似于 uniswapx * y= k 即流动性池。在传统的做商机制中,适用于作用大量资源并采用复合策略的公司,借助这种机制使得交易者可以在订单薄交易平台中获得优质的成交量。

自动化做商机制中。则将做市商的这一过程去中心化,让所有人都可以在区块链中创建市场

区块链概述

区块链(block chain)是由密码学与共识机制等技术所创建的庞大的交易资料区块链的点对点网络。我们可以理解为区块链中的每一个 “区块” 都蕴含着交易资料,以及前一个区块的加密散列、相应时间戳等信息。

区块链的形成主要分为主链,然后分出块,然后是存在于主链外的孤儿链,需要注意的是,每次更新都是一个新的块,添加至链的末端。

欧盟在区块链教育中,将区块链比喻成一种分布式的账本,为社区记录和共享信息所提供了一种方式。

在这各社区中每个成员可以维护他自己的副本,而所有的成员必须集体验证任何更新,通常这些信息可以表示交易、合约、资产、身份或者实际上人何以数字所描述的东西。这些信息是永久且透明的,可搜索使得社区成员可以完整的查看交易历史。

节点 -> 链 -> 区块

一个节点中是一个完整的单元,节点里面的链上拥有着多个区块,而区块中存放着多个数据,每一个节点或者说一个链中都拥有不同的共识机制,公有链中,所采用的共识机制主要是 PoW/PoS 等,是一个去中心化的节点,同时也是所有人都可以参与的。

而联盟链来说,他的参议机制是联盟成员,采用的共识机制是分布式一致性算法,通常用于供应链的管理和金融服务、医疗保健等。最后私有链则是 skik/pbft 等作为共识机制,参与者通常是链的所有者。

共识机制

共识机制(consensus) 可以理解为达成共识的机制,在分布式系统中最为常见,同时依据故障组的容错能力,常被分为崩溃容错协议(crash fault tolerant) 以及拜占庭容错协议(Byzantine fault tolerant)

PoW

我们以公有链中的共识机制为切入点,工作量(proof of work)证明主要被称之为挖矿,之后获胜者以或者代币做为食用计算能力的激励措施,耗费大量的电力和实践以及性能,来生成区块,

PoS

权益证明(Proof-of-Stake) 于 PoW 相比,这种是发通过其账户余额来选择节点,通常是最富有经验者或者来主导网络,它的好处在于,减少了能源的使用并改善于 PoW 相关的电力效率低下而创建的。

于 PoW 之间的区别在于选举他们所代表来验证区块,因此不诚实的代表容易被投票淘汰,相反于 PoS 每个利益相关者都会验证交易,因此 PoS 更加严格。

容错类型

计算系统由大量的硬件和软件组成,特别是在区块链的场景中,一旦某个块出现了问题,那么将会对整个网络发生较为较为不可恢复性的伤害,因此在设计中每个区块拥有良好的故障处理行为,尽管发生故障,他们仍然可以继续提供特定的标准服务,

然而对于越来越多的用户群体来说这些不可预测和潜在的危险故障导致服务的不可用的代价可能非常大,因此就需要依赖于容错服务。我们在接触分布系统中,对容错的类型都因有大致的了解。

我们需要了解的一个概念是,为了实现容错,分布式系统架构中采用了沉余的处理方式,也就是集群,在 HBASE 分布式数据库中就大致的依赖 Zookeeper + Hadoop 中的 datanode和 namenode 来设计的容错模式。

对于服务的崩溃,我们可以通过 Flaviu Cristian 所写的 Understanding Fault-Tolerant Distributed Systems 来理解容错分布式系统。

CFT

分布式系统中面临着很多问题,某个节点中出现问题或者故障,又或者是网络出现了问题,那么对于生产环境来说,共识算法必须可以应对这种故障。

CFT(Crash fault tolerant,崩溃容错协议) 在协议中构建了一定的复原能力,通过算法正确的推进进程以此来达到共识,即使某些组件出现了故障。

通过 # The University of Iowa 内,关于故障和容错的 章节中我们可以明白崩溃容错协议的主要用处,由此可知,崩溃失败就是进程停止,他是无法逆转的,如果一个系统无法容忍失败,也就是崩溃,也就是停止失败,他也无法容忍崩溃。

BFT

拜占庭容错(Byzantine fault tolerant)是容错分布式计算及系统对组件故障的抵抗

拜占庭容错(BFT) 是分布式网络的功能,即使网络中某些节点无法响应或者相应不正确,也可以达成某种狗狗是,通古果采用集体决策来防止系统故障,以此来减少影响,对于拜占庭故障的类型主要分为两类,一种是故障的停止,或者是节点的故障,如今他已经被应用在区块链的交易中拜占庭断层 - 概述|科学直接主题 (sciencedirect.com)

区块链平台将其作为共识的机制,通常拜占庭还包括的拜占庭容错(BFT)和实用拜占庭容错(pBFT)。

拜占庭错误的定义为分布式系统在执行算法是所发生的任意错误,当拜占庭式错误发生时,系统可能会以任意的形式进行反应,这是传统的拜占庭错误。

但当我们使用拜占庭容错时,主要会涉及到同步和异步,因此,同步时系统在已知有限时间内所作出相应的系统,而异步则不是。

自 Miguel Castro 与 Barbara Liskov 等人在 1999 年 2 月所提出的实用拜占庭容错(BFT) 他们通过实用数字签名来跨多个跳认证用户,即密码学需要一个可信的基础设施来发放他们的公钥和私钥,因此假设这项基础问题处发现问题,则整个网络也会失败。

对于拜占庭分层,我们可以通过阅读 MA Nasreen,Amal Ganesh, Sunitha C 等人在 2016 年第四届计算机科学与工程最新趋势国际会议所提出的A Study on Byzantine Fault Tolerance Methods in Distributed Networks (sciencedirectassets.com)

为了达成一个安全的共识协议,他必须是容错的,所以 BFT 中开发了实用拜占庭容错(PBFT),这种是基于BFT原则的验证,并且使用选举过程中的块是在验证之后所进行的

1
2
3
共识,即在添加分类帐上所有的条目在此之前都需要进行某种形式的共识,**并且通过已知参与者之间的算法进行投标来达成某种共识**,诸如工作量证明(Pow)和权益证明(Pos)分别在验证工作和交易的共识协议,同样的还有其他方法,如实用拜占庭容错(BPFT)和委托权益证明(DPos) 都是用于达成某种共识的。

对于 BFT 可以阅读拜占庭将军的问题,同时拜占庭容错是一个定义容许拜占庭将军问题失败的了别的系统特征,同时还有拜占庭故障(Byzantine Failure)

实用拜占庭容错是设计在为异步请求的响应中没有上线的系统中高效工作,阵地低开开销时间进行 优化,目标是解决已经可用的拜占庭容错解决方案中的多个问题,通常应用于分布式计算中和区块链。

合约

智能合约是一种自动执行的合同,由买卖双方之间的协议条款直接写入代码行中,分散在区块链网络中,通过代码控制执行,他也允许在不同的匿名方之间执行可信交易和协议,无需中央机构进行管理,符合去中心化的理论和趋势。

智能合约也是一种计算机程序或交易程序,目的是减少可信中介人的需求,仲裁和执行成本,用来减少恶意的异常,他只是区块链中上存储的程序,在满足一定条件的时候执行,通常用于自动执行协议,以便所有参与者都可以立即确定结果,而不需要中介人的参与来减少时间损失。

合约可以在满足条件的时候触发下一个操作并且开发者通过 ABI 来进行接口的调用和操作,在目前,智能合约的概念已经被运用到供应商关系的信任和国际贸易,使得交易双方更快、更高效。

智能合约是区块链中的基础技术,同时也是以太坊网络中的关键要素,智能合约是自动执行的一组 Code,然后在区块链上进行验证。可以将智能合约理解成传统意义上的合同,同样是多方之间的协议,其中以方向另一方提供有价值的东西,而且交易双方要被智能合约所约束。

他与传统的交易来进行对比,不同之处在于,智能合约可以自动执行协议条款中的 Code,然后 Code 会发送到区块链上的地址,由该区块的共识机制进行验证,一旦交易包含在此区块中,那么就会执行智能合约且发生不可挽回的操作。

在智能合约中,消除了传统 CeFi 中的中介以及合同的执行需求,简化了合同的谈判过程,主要通过 Code 来定义交易的机制,从而成为条款的仲裁者。

但智能合约也有缺点,就是如果智能合约中的 Code 出现或存在错误,则会使得智能合约无效,且不可更改。因为智能合约是无信任、自主、分散且透明的,一旦部署他就是不可逆以及不可修改的存在。

计算机科学精粹预备知识

计算机科学(Computer science,CS) 是系统性研究信息与计算机理论基础和系统的实践以及应用类的学科,如同天文学等,从本质上来讲计算机科学与科学同样具有统一性。但实际上计算机科学相当的数量领域都不涉及计算机科学研究的本身。

1
正因为计算机科学的门类有很多,所以更多的院系和研究者更加倾向于 **computing secience**或 **datalogy** 即数据解析,表示计算机科学是围绕着数据和数据处理,不一定要涉及计算机。

sass 简介与安装

sass 是什么

sass是世界上最成熟、最稳定、最强大的专业级css扩展语言,全称“Syntactically Awesorme Stylesheets”即审计准则说明书,最初是由Hampton Catlin设计,Natalie Weizenbaum开发的叠层样式表设计语言。在完成最初版本的开发后,开发证体哦继续通过SassScript来扩充其功能,而SassScript是Sass文件使用的小型脚本语言,其中SassScript用于将.cass文件转换成.css文件。

一个问题让你爱上sass

问:我有好多重复的css,但是我又不想重新写或复制
答:你可以使用sass的变量进行引用,如:

1
2
3
4
$one:  10px;
body {
font-size: $one;
}

安装 sass

本文主要通过opensuse进行安装sass,可通过 sudo zypper install ruby2.5-rubygem-sass进行安装,之后使用其sass命令来证明sass是否安装,当然也可通过opensuse所提供的官方软件仓库中进行图形界面安装,总之只要可以安装就行了。

CSS nth-child and calc as well as position:hover


nth-child 根据 MDN 的概述中的作用为找到所有当前元素的兄弟元素,然后按照先后顺序从1开始进行排序,而calc的作用则是允许在声明 CSS属性中执行计算

那么通过使用 nth-child 和 calc 以及 position 和 :hover也许会实现出一种根据鼠标移动而移动的效果,具体可以使用多个元素进行定义,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+SC:100,300,400,500,700,900">
</head>
<body>
<div class="cell"></div>
<!-- 99 -->
<div class="con">
<div class="squ"></div>
</div>
</body>
</html>

那么 SCSS 样式可以为他设置一个基础的背景颜色和网格让其显得更好理解,那么首先我们将con的X,Y位置设置为0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
*, *::before, *::after {
padding: 0;
margin: 0 auto;
box-sizing: border-box;
}
body {
background-color: black;
height: 100vh;
// 设置网格
display: grid;
grid-template: repeat(10, 1fr) / repeat(10, 1fr);
}
.cell {
width: 100%;
height: 100%;
border: 1px solid white;
z-index: 2;
}
.con {
--positionX: 0;
--positionY: 0;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
}
.squ {
width: calc(100px + var(--positionX) * 20px);
height: calc(100px + var(--positionY) * 20px);
background: white;
transition: all 0.3s;
}

之后通过将 cell使用nth-child:hover来进行绑定con的位置数据:

1
2
3
4
5
6
7
8
@for $i from 0 to 10 {
.cell:nth-child(10n + #{$i + 1}):hover ~ .con {
--positionX: #{$i};
}
.cell:nth-child(n + #{10 * $i + 1}):nth-child(-n + #{10 * ($i + 1)}):hover ~ .con {
--positionY: #{$i};
}
}

CSS(通过 CSS 则更加直观)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.cell:nth-child(10n + 1):hover ~ .con {
--positionX: 0; }

.cell:nth-child(n + 1):nth-child(-n + 10):hover ~ .con {
--positionY: 0; }

.cell:nth-child(10n + 2):hover ~ .con {
--positionX: 1; }

.cell:nth-child(n + 11):nth-child(-n + 20):hover ~ .con {
--positionY: 1; }

.cell:nth-child(10n + 3):hover ~ .con {
--positionX: 2; }

.cell:nth-child(n + 21):nth-child(-n + 30):hover ~ .con {
--positionY: 2; }

.cell:nth-child(10n + 4):hover ~ .con {
--positionX: 3; }

当鼠标移动到到 cell 1或21……的时候,则会改变.con相应位置信息来达到使样式移动的效果(配合上过渡)。

CSS spirit

spirit```即**雪碧图**,或**CSS 精灵**,是一种CSS图像拼合技术,```主要将将图标或图像合并到一张图片中```然后根据背景定位来进行获取,这种方式可以使用```background-position```或```background```属性进行渲染,也可通过工具直接进行框选,如:```http://tools.jb51.net/code/css_sprite```。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

使用雪碧图的优点是可以减少加载网页时对服务器的请求次次数,可以合并多数的图片和小图标,不需要多个图片分别进行请求,同时```提高了页面的加载速度```。

> 本文我们通过使用阿里巴巴矢量图库内刺栗壳所提供的 icon 来进行演示,图片下载地址:https://gitee.com/analysis-of-river-snow/draw>ing-bed/raw/master/20210421225013.png
> 配合 http://tools.jb51.net/code/css_sprite 进行绘制

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
<link rel="stylesheet" href="http://analysis-of-river-snow.gitee.io/xue-css/less/xue.css">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+SC:100,300,400,500,700,900">
</head>
<body>
<div class="xu-col-3">
<div class="or">
<p class="title"><span class="on-btn-1"></span>当感到无趣时</p>
<h1>让我们与世界交流下</h1>
</div>
<div class="or" style="text-align: right">
<p class="title"><span class="on-btn-2"></span>人生本芳华,不如</p>
<h2>定个闹钟提醒自己</h2>
</div>
<div class="or">
<p class="title"><span class="on-btn-3"></span>任何的想法</p>
<h2>拥有有实现的可能</h2>
</div>
<div class="or" style="text-align: right">
<p class="title"><span class="on-btn-4"></span>所有的肯定</p>
<h2>都是失败的积累</h2>
</div>
<div class="or">
<p class="title"><span class="on-btn-5"></span>满意时的笑容</p>
<h2>却抹去不了背后的付出</h2>
</div>
<div class="or" style="text-align: right">
<p class="title"><span class="on-btn-6"></span>爆发时</p>
<h2>小宇宙内蕴含无限可能</h2>
</div>
<div class="or">
<p class="title"><span class="on-btn-7"></span>世界很美</p>
<h2>打开快手,记录美好时光!</h2>
</div>
</div>
</body>
</html>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
body {
box-sizing: border-box; }

.layout {
margin-left: 50%;
margin-top: 10%; }

.title {
font-weight: 300;
color: #7200ff; }

.on-btn-1 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -13px -25px;
width: 28px;
height: 17px; }

.on-btn-2 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -75px -20px;
width: 25px;
height: 24px; }

.on-btn-3 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -136px -19px;
width: 26px;
height: 26px; }

.on-btn-4 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -200px -18px;
width: 21px;
height: 28px; }

.on-btn-5 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -15px -89px;
width: 25px;
height: 24px; }

.on-btn-6 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -16px -160px;
width: 24px;
height: 21px; }

.on-btn-7 {
background: url("https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210421225013.png") no-repeat;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
background-position: -76px -91px;
width: 25px;
height: 20px; }

/*# sourceMappingURL=style.css.map */
📖 more posts 📖