您正在查看: Ethereum-新手教程 分类下的文章

web3j 监听 Solidity Funcion event

假设您有一个非常简单的合同,可以递增和递减部署到该地址的计数器 CONTRACT_X

pragma solidity ^0.4.20;

contract Counter {
    int counter; // Global state

    event CounterIncremented(address indexed _by, int _newValue);
    event CounterDecremented(address indexed _by, int _newValue);

    function increment(int _value) public {
        counter = counter + _value;
        emit CounterIncremented(msg.sender, counter);
    }

    function deincrement(int _value) public {
        counter = counter - _value;
        emit CounterDecremented(msg.sender, counter);
    }
}

事件定义哈希

首先,您必须定义每个事件(定义),以便计算代表该事件在网络上的唯一哈希。

// Definition of event CounterIncremented(address indexed _by, int _newValue)
public static final Event INCREMENT_EVENT = new Event("CounterIncremented", 
    Arrays.<TypeReference<?>>asList(new TypeReference<Address>(true) {}, new TypeReference<Int>(false) {}}));

// Definition of event CounterDecremented(address indexed _by, int _newValue)
public static final Event DECREMENT_EVENT = new Event("CounterDecremented", 
    Arrays.<TypeReference<?>>asList(new TypeReference<Address>(true) {}, new TypeReference<Int>(false) {}}));

然后,要计算事件的哈希,您只需要执行以下操作:

private static final String INCREMENT_EVENT_HASH = EventEncoder.encode(INCREMENT_EVENT);

private static final String DECREMENT_EVENT_HASH = EventEncoder.encode(DECREMENT_EVENT);

筛选

在订阅事件之前,可以应用过滤器,因为根据定义,可以查询以太坊事件日志(网络所有智能合约的所有事件)。

按区块范围和智能合约过滤

返回智能合约的所有不同类型的事件CONTRACT_X。在我们的情况下,我们将获得CounterIncremented和CounterDecremented事件。

EthFilter filter = new EthFilter(
    DefaultBlockParameterName.EARLIEST, // From block 0
    DefaultBlockParameterName.LATEST,  // To last block
    CONTRACT_X); // Unique Smart Contract

EthFilter filter = new EthFilter(
    DefaultBlockParameterName.LATEST, // only the latest block  
    DefaultBlockParameterName.LATEST,  // 
    CONTRACT_X); // Unique Smart Contract

EthFilter filter = new EthFilter(
    DefaultBlockParameterName.valueOf("2222"), // From block no 2222
    DefaultBlockParameterName.LATEST,  // To latest
    Arrays.asList(address1, address2, address3)); // List of Smart Contracts

LATEST意味着您将提取订阅期间出现的事件。

  • 按事件过滤
    如果要按事件类型过滤,例如仅获取CounterIncremented事件,则可以使用属性addSingleTopic
    EthFilter filter = new EthFilter(
      DefaultBlockParameterName.EARLIEST, // From block 0 
      DefaultBlockParameterName.LATEST,  // To latest
      CONTRACT_X) // Unique Smart Contract
    .addSingleTopic(INCREMENT_EVENT_HASH);
  • 按事件参数过滤
    最后,您可能希望按事件参数进行过滤,例如,CounterIncremented由给定地址触发的所有事件(按事件的参数_by进行过滤CounterIncremented)
    EthFilter filter = new EthFilter(
      DefaultBlockParameterName.EARLIEST, // From block 0
      DefaultBlockParameterName.LATEST,  // To latest
      CONTRACT_X) // Unique Smart Contract
    .addSingleTopic(INCREMENT_EVENT_HASH)
    .addOptionalTopic("0xdDd6427Aaf3766DC97A9cA9deDD3e7911b085B6B");

    事件参数过滤器仅适用于“索引”参数。

    订阅活动

    最后,最后一步是订阅节点的事件:

    web3.ethLogFlowable(filter).subscribe(event -> { 
      event.getAddress(); // Smart contract address
      event.getBlockNumber(); // Block number
      event.getTransactionHash(); // Transaction that emitted the event
      event.getTopics().get(0); // Event hash
      event.getTopics().get(1-n); // Event parameter (1) _by, (2) _value
    }); 

    参考

    https://ethereum.stackexchange.com/questions/66379/recover-solidity-funcion-event-in-web3j
    http://docs.web3j.io/latest/advanced/filters_and_events/

MyEtherWallet 本地部署

编译运行

git clone https://github.com/MyEtherWallet/MyEtherWallet.git
cd MyEtherWallet/
npm i
npm run start:ci

外网访问

https://github.com/MyEtherWallet/MyEtherWallet/blob/1e76e24312d21a447d35f0810c5431dbdb7432ee/vueConfig/mew.js#L10

 devServer: {
    https: true, // 是否默认https
    host: 'localhost', // 访问地址
    hotOnly: true,
    port: 8080,  //端口
    headers: defaultConfigs.headers // 删掉
  },

eth poa 链加油站gasprice

部署安装

git clone https://github.com/bcskill/eth-gasprices.git
cd eth-gasprices
pip3 install -r requirements.txt

服务运行

export ETH_RPC_URL=http://ip:8545
python3 gasprice.py -h 0.0.0.0 -p 8000
服务启动
cp gasprice.service /etc/systemd/system/gasprice.service
systemctl daemon-reload
systemctl start gasprice.service
systemctl status gasprice.service

或者

python3 gasprice.py -h 0.0.0.0 -p 8000 "$@" > ./stdout.txt 2> ./stderr.txt &  echo $! > ./nodeos.pid
tail -f stderr.txt

测试访问

http://127.0.0.1:8000/

测试数据

{
    "health": true,
    "block_number": 26972,
    "block_time": 2.261,
    "slow": 24,
    "standard": 25,
    "fast": 54.955,
    "instant": 100
}
数据解释
  • slow 慢
  • standard 标准
  • fast 快速
  • instant 即时

“慢”,“标准”,“快速”和“即时”值代表最近200个区块的最低汽油价格。 默认情况下,慢表示30%的概率,标准为60%,快为90%,即时为100%。

常见问题

numpy: Something is wrong with the numpy installation.
python3 gasprice.py
Traceback (most recent call last):
  File "gasprice.py", line 4, in <module>
    import pandas as pd
  File "/home/surou/.local/lib/python3.6/site-packages/pandas/__init__.py", line 17, in <module>
    "Unable to import required dependencies:\n" + "\n".join(missing_dependencies)
ImportError: Unable to import required dependencies:
numpy: Something is wrong with the numpy installation. While importing we detected an older version of numpy in ['/home/surou/.local/lib/python3.6/site-packages/numpy']. One method of fixing this is to repeatedly uninstall numpy until none is found, then reinstall this version.
解决方法
rm -rf ~/.local/lib/python3.6/site-packages/numpy
pip install numpy
No module named 'click'
ModuleNotFoundError: No module named 'click'
解决方法
pip3 install click

Web3.py 安装和使用

安装python3

 sudo apt-get install python3.6

设置python3默认

sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 150
sudo update-alternatives --config python

安装pip3

sudo apt-get install python3-pip

安装web3

pip3 install web3

测试合约代码

import time
from web3 import Web3
from web3.contract import Contract, ContractFunctions
from web3 import Web3

false = False
true = True
CONTRACT_ADDRESS = "0xD8B0c34024deA0B9ABaf187E58Dbb3e81a033367"
CONTRACT_ABI = [{"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":"success","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":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_value","type":"uint256"}],"name":"burnFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","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":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initialSupply","type":"uint256"},{"name":"tokenName","type":"string"},{"name":"tokenSymbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"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"},{"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":false,"name":"value","type":"uint256"}],"name":"Burn","type":"event"}]

w3 = Web3(Web3.HTTPProvider('http://。。。:8545'))
acct = w3.eth.account.privateKeyToAccount("e9bc9ae61053。。。。。69fd59d7986b9f4f49c025cc")

if __name__ == "__main__":
    print("getTransactionCount:", w3.eth.getTransactionCount(acct.address))
    print("gasPrice:", w3.eth.gasPrice)

    contract = w3.eth.contract(address=Web3.toChecksumAddress(CONTRACT_ADDRESS), abi=CONTRACT_ABI)
    TokenConstruct_txn = contract.functions.transfer(Web3.toChecksumAddress("0xc65dD4299C682f335d6e15e2B5774D015E01E479"), w3.toWei(2, 'ether')).buildTransaction({
        'from': acct.address,
        'nonce': w3.eth.getTransactionCount(acct.address),
        'gas': 100000,
        'gasPrice': w3.eth.gasPrice})
    TokenSigned = acct.signTransaction(TokenConstruct_txn)
    print("Pre-calculated transactionHash:", w3.toHex(w3.sha3(TokenSigned.rawTransaction)))
    TokenTx_hash = w3.eth.sendRawTransaction(TokenSigned.rawTransaction)
    print("transactionHash:", TokenTx_hash.hex())
    #TokenTx_receipt = w3.eth.waitForTransactionReceipt(TokenTx_hash)
    #TokenContract_address = TokenTx_receipt['contractAddress']
    #print("Contract Deployed At:", TokenContract_address)

参考

https://web3py.readthedocs.io/en/latest/quickstart.html

基于以太坊定制链部署Uniswap

项目定制

由于Uniswap 是为以太坊公链设计的,所以前端里面和合约有一些配置是代码写死的,所以我们需要先修改下

前端修改

前端代码地址:https://github.com/Uniswap/uniswap-interface
前端依赖以下几个npm包

  • uniswap-sdk @uniswap/sdk
  • default-token-list @uniswap/default-token-list

主要修改以下几点

修改uniswap-sdk

代码地址:https://github.com/Uniswap/uniswap-v2-sdk
我们先看下前端依赖的sdk版本

"@uniswap/sdk": "3.0.3",

可以看到项目依赖的是3.0.3,查看代码,并没有相应的tag..,只是个commit,这个仓库git用的真是令人发指。。

由于需要我们自己维护这个库的数据,所以我们直接基于上面的commit fork下。
fork后的测试仓库:https://github.com/cppfuns/uniswap-sdk

修改网络

由于目前Uniswap支持eth主网,以及各个测试网,这并不是我们需要的,我们的定制链只支持主网和测试网。
修改ChainId为所需要的id以及选项

export enum ChainId {
  MAINNET = 65524,
  TESTNET = 65525,
}

修改合约地址

这个等后面部署完合约再来修改,先记下
然后修改下工厂合约的地址和code hash

修改WETH地址

在定制链主网和测试网上分别部署WETH合约,修改对应的合约地址

export const WETH = {
  [ChainId.MAINNET]: new Token(ChainId.MAINNET, '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', 18, 'WETH', 'Wrapped Ether'),
  [ChainId.TESTNET]: new Token(ChainId.TESTNET, '0x73DcdfeBe2b1Db8FAe6f0A5AA0f35C3BaDa6811A', 18, 'WETH', 'Wrapped Ether')
}

修改default-token-list

fork: https://github.com/cppfuns/default-token-list.git
根据网络需要修改相应的配置

修改uniswap-interface

修改运行节点环境

由于我们是定制链,没有infura,所以修改为我们自己定制链的网络环境

REACT_APP_CHAIN_ID="链id"
REACT_APP_NETWORK_URL="http://节点地址"

修改网络配置

NETWORK_LABELS默认的主网不需要添加

const NETWORK_LABELS: { [chainId in ChainId]?: string } = {
  [ChainId.TESTNET]: 'testnet'
}

FormaticSupportedChains

type FormaticSupportedChains = Extract<ChainId, ChainId.MAINNET | ChainId.TESTNET>

CHAIN_ID_NETWORK_ARGUMENT

const CHAIN_ID_NETWORK_ARGUMENT: { readonly [chainId in FormaticSupportedChains]: string | undefined } = {
  [ChainId.MAINNET]: undefined,
  [ChainId.TESTNET]: 'testnet'
}

EMPTY_LIST

const EMPTY_LIST: TokenAddressMap = {
  [ChainId.TESTNET]: {},
  [ChainId.MAINNET]: {}
}

ETHERSCAN_PREFIXES

const ETHERSCAN_PREFIXES: { [chainId in ChainId]: string } = {
  65524: '',
  65525: 'testnet.'
}

prefix

const prefix = `https://${ETHERSCAN_PREFIXES[chainId] || ETHERSCAN_PREFIXES[65524]}etherscan.io`
可支持的链id

修改MetaMask可以支持的链id,否则无法连接

export const injected = new InjectedConnector({
  supportedChainIds: [65524, 65525]
})

修改合约地址

下面提到的合约,都可以去https://etherscan.io/address/合约地址#code 去查看,然后编译,部署到自己的定制网络中

修改ROUTER_ADDRESS

ROUTER_ADDRESS

各个主网的代币地址

代币地址

export const DAI = new Token(ChainId.MAINNET, '0x5D0624A7401ecB5075eDFd4855D3b9d8909Da744', 18, 'DAI', 'Dai Stablecoin')
export const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6, 'USDC', 'USD//C')
export const USDT = new Token(ChainId.MAINNET, '0xdAC17F958D2ee523a2206206994597C13D831ec7', 6, 'USDT', 'Tether USD')
export const COMP = new Token(ChainId.MAINNET, '0xc00e94Cb662C3520282E6f5717214004A7f26888', 18, 'COMP', 'Compound')
export const MKR = new Token(ChainId.MAINNET, '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', 18, 'MKR', 'Maker')
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
export const WBTC = new Token(ChainId.MAINNET, '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', 8, 'WBTC', 'Wrapped BTC')
export const GOVERNANCE_ADDRESS = '0x5e4be8Bc9637f0EAA1A755019e06A68ce081D58F'
export const TIMELOCK_ADDRESS = '0x1a9C8182C09F50C8318d769245beA52c32BE35BC'
const UNI_ADDRESS = '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984'
修改对应网络UNI地址

修改代码

export const UNI: { [chainId in ChainId]: Token } = {
  [ChainId.MAINNET]: new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap'),
  [ChainId.TESTNET]: new Token(ChainId.TESTNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap')
}
修改WETH_ONLY地址

WETH_ONLY

const WETH_ONLY: ChainTokenList = {
  [ChainId.MAINNET]: [WETH[ChainId.MAINNET]],
  [ChainId.TESTNET]: [WETH[ChainId.TESTNET]]
}
修改多签合约地址

MULTICALL_NETWORKS

const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = {
  [ChainId.MAINNET]: '0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441',
  [ChainId.TESTNET]: '0x2A16f8A9C88Ddaad5928D85Ce065940b7b25E11c'
}
修改V1_FACTORY_ADDRESSES

V1_FACTORY_ADDRESSES v1版本暂时用不到,修改只是为了网络配置

修改getColorFromToken

getColorFromToken,特殊地址,主要是为了网络配置

修改useENSRegistrarContract

useENSRegistrarContract,特殊地址,主要是为了网络配置

修改代币获取列表

在线获取地址

修改获取地址,由于目前没有在线地址,所以都先暂时删除了

修改未支持的代币列表

列表地址暂时删除

修改依赖包

uniswap-interface

 "@uniswap/sdk": "https://github.com/cppfuns/uniswap-sdk.git",
"@uniswap/default-token-list": "https://github.com/cppfuns/default-token-list.git"