3.ERC20对接

本文写于2019

ERC20 签名

https://zhuanlan.zhihu.com/p/39656584

签名要点:
  • To地址是ContractAddress

  • data是代币调用智能合约的 transfer(address, uint256) 方法编码数据

     0xa9059cbb + 对方的转账地址hex + 转账的值的hex       //其中0xa9059cbb代表某个代币的转账方法hex(transfer)
    

ABI 是什么

https://www.cnblogs.com/tinyxiong/p/9453563.html

ABI 全称是 Application Binary Interface,翻译过来就是:应用程序二进制接口,简单来说就是 以太坊的调用合约时的接口说明。还不是很理解,没关系。

自己发布ERC20代币

https://learnblockchain.cn/2018/01/12/create_token/

编译器选择 v0.4.17

我发行的 ERC20 Token 地址

https://rinkeby.etherscan.io/address/0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33


> eth.getTransactionReceipt("0x1a24c6110139e963a901d30937bf299753fd0574c3c796dcb0379b1ae4171841")
{
  blockHash: "0x971e6e1cd533d7332d3fb38be084c2199a589ea9d2dfb2e5e9a6e01379556fba",
  blockNumber: 4988294,
  contractAddress: null,
  cumulativeGasUsed: 338664,
  from: "0x954d1a58c7abd4ac8ebe05f59191cf718eb0cb89",
  gasUsed: 53418,
  logs: [{
      address: "0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33",
      blockHash: "0x971e6e1cd533d7332d3fb38be084c2199a589ea9d2dfb2e5e9a6e01379556fba",
      blockNumber: 4988294,
      data: "0x000000000000000000000000000000000000000000008a8ed1b5a15792880000",
      logIndex: 2,
      removed: false,
      topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000954d1a58c7abd4ac8ebe05f59191cf718eb0cb89", "0x00000000000000000000000056e5782c908f69bd46b7e77338349f961fbe55b1"],
      transactionHash: "0x1a24c6110139e963a901d30937bf299753fd0574c3c796dcb0379b1ae4171841",
      transactionIndex: 3
  }],
  logsBloom: "0x00000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000050000000000000000000000000000000000000000000000400000000000000000000000000020000000000000000000000000000000000200000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000004000000000000000000000",
  status: "0x1",
  to: "0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33",
  transactionHash: "0x1a24c6110139e963a901d30937bf299753fd0574c3c796dcb0379b1ae4171841",
  transactionIndex: 3
}


  • logs.address: 是合约的地址
  • logs.data: 是交易额(十六进制)
  • topic[0] : 是事件的 keccka(function(from, to, value)) hash值
  • topic[1]: from (token的发送方)
  • topic[2]: to (token的接收方)

ERC20转账

#!coding:utf8

#author:yqq
#date:2019/8/28 0028 14:22
#description:  ETH 普通转账  /  ERC20 代币转账

from ethereum.transactions import  Transaction
import rlp
from rlp.sedes import big_endian_int , binary
from decimal import  Decimal



#普通的ETH转账成功的案例: https://rinkeby.etherscan.io/address/0x56e5782c908f69bd46b7e77338349f961fbe55b1
#ERC20-Token的转账成功案例: https://rinkeby.etherscan.io/tx/0xfa8da3dda31d644a5f654fc332284cafc2367990a529a14fdb0085b2e89259aa
#ERC20-Token 假交易的案例: https://rinkeby.etherscan.io/tx/0xa5c51ead7f209ac97fb8d8685171e2a5fc50bfb98b987cb6e3342670e9919b3a
#

Mainnet=0
Rinkeby=4


def to_zero_padded_str(in_data, target_len=64):
    # print(in_data)
    return '0' * (target_len - len(in_data)) + in_data


def make_data(abi_transfer='a9059cbb', to='0x123423', value=0x123424):
    return abi_transfer + to_zero_padded_str(to[2:]) + to_zero_padded_str(hex(int(value))[2:].replace('L', ''))
    pass


def main():

    erc20_data =  make_data(to='0x56e5782c908f69bd46b7e77338349f961fbe55b1', value=Decimal('2019.08281809')*(10**18))
    print( "erc20_data:{}".format( erc20_data) )

    tx = Transaction(nonce=120,
                     gasprice=10*(10**9),
                     startgas=210000,
                     to='0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33',
                     value=1*(10**16),
                     # data=b''
                     data = erc20_data.decode('hex')
                     )
    tx.sender = '0x954d1a58c7abd4ac8ebe05f59191cf718eb0cb89'

    # print(tx.hash)
    signed_tx  =  tx.sign(key='DBBAD2A5682517E4FF095F948F721563231282CA4179AE0DFEA1C76143BA9607', network_id=Rinkeby)  # 4:Rinkeby
    print( signed_tx.hash.encode('hex'))
    rlp_data = rlp.encode(  rlp.infer_sedes(tx).serialize(tx) )
    print(rlp_data.encode('hex'))
    # print(signed_tx)

    pass


def main2():

    erc20_data =  make_data(to='0xdf88522B56B85d4F0Bb08a7494b97E017BC6CB31', value=Decimal('656340.20627410')*(10**18))
    print( "erc20_data:{}".format( erc20_data) )

    tx = Transaction(nonce=51,
                     gasprice=10*(10**9),
                     startgas=210000,
                     to='0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33',
                     value=1*(10**16),
                     # data=b''
                     data = erc20_data.decode('hex')
                     )
    tx.sender = '0x56e5782c908f69bd46b7e77338349f961fbe55b1'

    # print(tx.hash)
    signed_tx  =  tx.sign(key='63C08FABC252B53B9471E520CE8199971DB8884B5B569CBBBD17BC714E6BB39F', network_id=Rinkeby)  # 4:Rinkeby
    print( signed_tx.hash.encode('hex'))
    rlp_data = rlp.encode(  rlp.infer_sedes(tx).serialize(tx) )
    print(rlp_data.encode('hex'))
    # print(signed_tx)

    pass

# 
# import ethereum.utils
# def main3():
# 
#     utils.sha3('')
# 
# 
# 
# 
#     pass



if __name__ == '__main__':

    # main()
    main2()
    # main3()


成功的ERC20 Token转账

> eth.getTransactionReceipt("0xa5c51ead7f209ac97fb8d8685171e2a5fc50bfb98b987cb6e3342670e9919b3a")
{
  blockHash: "0xc789baa019defb946c10679782a93f1a333a9c89f3e21bb05faca250b0cc9c3d",
  blockNumber: 4989987,
  contractAddress: null,
  cumulativeGasUsed: 24409,
  from: "0x56e5782c908f69bd46b7e77338349f961fbe55b1",
  gasUsed: 24409,
  logs: [],  //日志为空
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  status: "0x0", //状态为0
  to: "0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33",
  transactionHash: "0xa5c51ead7f209ac97fb8d8685171e2a5fc50bfb98b987cb6e3342670e9919b3a",
  transactionIndex: 0
}
> 

> eth.getTransactionReceipt("0xfa8da3dda31d644a5f654fc332284cafc2367990a529a14fdb0085b2e89259aa")
{
  blockHash: "0xe639442fc8b9201e674dfffe2738ced535034324ebc533d429be7305c2407a28",
  blockNumber: 4989937,
  contractAddress: null,
  cumulativeGasUsed: 614873,
  from: "0x954d1a58c7abd4ac8ebe05f59191cf718eb0cb89",
  gasUsed: 38418,
  logs: [{
      address: "0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33",
      blockHash: "0xe639442fc8b9201e674dfffe2738ced535034324ebc533d429be7305c2407a28",
      blockNumber: 4989937,
      data: "0x00000000000000000000000000000000000000000000006d7467257e5d192400",
      logIndex: 7,
      removed: false,
      topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000954d1a58c7abd4ac8ebe05f59191cf718eb0cb89", "0x00000000000000000000000056e5782c908f69bd46b7e77338349f961fbe55b1"],
      transactionHash: "0xfa8da3dda31d644a5f654fc332284cafc2367990a529a14fdb0085b2e89259aa",
      transactionIndex: 10
  }],
  logsBloom: "0x00000000000000000000000000040000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000050000000000000000000000000000000000000000000000400000000000000000000000000020000000000000000000000000000000000200000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000004000000000000000000000",
  status: "0x1",
  to: "0x130fc2749d35fe026f32427f60dd3f2ecb6c2f33",
  transactionHash: "0xfa8da3dda31d644a5f654fc332284cafc2367990a529a14fdb0085b2e89259aa",
  transactionIndex: 10
}

事件日志 和 logsBloom分析

  • 以太坊黄皮书中关于 logsBloom字段的描述

logsBloom: The Bloom filter composed from indexable information (logger address and log topics) contained in each log entry from the receipt of each transaction in the transactions list.

  • 以太坊源码中的实现
// go-ethereum/core/types/bloom9.go

// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package types

import (
	"fmt"
	"math/big"

	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
)

type bytesBacked interface {
	Bytes() []byte
}

const (
	// BloomByteLength represents the number of bytes used in a header log bloom.
	BloomByteLength = 256

	// BloomBitLength represents the number of bits used in a header log bloom.
	BloomBitLength = 8 * BloomByteLength
)

// Bloom represents a 2048 bit bloom filter.
type Bloom [BloomByteLength]byte

// BytesToBloom converts a byte slice to a bloom filter.
// It panics if b is not of suitable size.
func BytesToBloom(b []byte) Bloom {
	var bloom Bloom
	bloom.SetBytes(b)
	return bloom
}

// SetBytes sets the content of b to the given bytes.
// It panics if d is not of suitable size.
func (b *Bloom) SetBytes(d []byte) {
	if len(b) < len(d) {
		panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d)))
	}
	copy(b[BloomByteLength-len(d):], d)
}

// Add adds d to the filter. Future calls of Test(d) will return true.
func (b *Bloom) Add(d *big.Int) {
	bin := new(big.Int).SetBytes(b[:])
	bin.Or(bin, bloom9(d.Bytes()))
	b.SetBytes(bin.Bytes())
}

// Big converts b to a big integer.
func (b Bloom) Big() *big.Int {
	return new(big.Int).SetBytes(b[:])
}

func (b Bloom) Bytes() []byte {
	return b[:]
}

func (b Bloom) Test(test *big.Int) bool {
	return BloomLookup(b, test)
}

func (b Bloom) TestBytes(test []byte) bool {
	return b.Test(new(big.Int).SetBytes(test))

}

// MarshalText encodes b as a hex string with 0x prefix.
func (b Bloom) MarshalText() ([]byte, error) {
	return hexutil.Bytes(b[:]).MarshalText()
}

// UnmarshalText b as a hex string with 0x prefix.
func (b *Bloom) UnmarshalText(input []byte) error {
	return hexutil.UnmarshalFixedText("Bloom", input, b[:])
}

//生成过滤器
func CreateBloom(receipts Receipts) Bloom {
	bin := new(big.Int)
	for _, receipt := range receipts {
		bin.Or(bin, LogsBloom(receipt.Logs))
	}

	return BytesToBloom(bin.Bytes())
}

func LogsBloom(logs []*Log) *big.Int {
	bin := new(big.Int)
	for _, log := range logs {
		bin.Or(bin, bloom9(log.Address.Bytes()))   //将地址加入过滤器
		for _, b := range log.Topics {
			bin.Or(bin, bloom9(b[:]))  //将topics的元素加入过滤器
		}
	}

	return bin
}

//计算过滤器
func bloom9(b []byte) *big.Int {
	b = crypto.Keccak256(b)

	r := new(big.Int)

	for i := 0; i < 6; i += 2 {
		t := big.NewInt(1)
		b := (uint(b[i+1]) + (uint(b[i]) << 8)) & 2047
		r.Or(r, t.Lsh(t, b))
	}

	return r
}

var Bloom9 = bloom9

func BloomLookup(bin Bloom, topic bytesBacked) bool {
	bloom := bin.Big()
	cmp := bloom9(topic.Bytes())

	return bloom.And(bloom, cmp).Cmp(cmp) == 0  //验证 topic是否在过滤中
}


  • ETH区块头的信息, 区块头中logsBloom字段包含了所有交易的logs的logsBloom


> eth.getBlockByNumber("0x7f6414", false)
{
  difficulty: "0x80ef294c2069a",
  extraData: "0x5050594520737061726b706f6f6c2d6574682d636e2d687a",
  gasLimit: "0x7a2310",
  gasUsed: "0x7a1c34",
  hash: "0x6eabf54758b981adf0736ec5521593199b64d1af668120eacb9dea665c85a5f9",
  logsBloom: "0xd82011ccca1160c828c342000bcad811448c8290041c342a08c284a8001c106e601401400889090808965c029248094602600e8e0bc0149f03b001ce0039a8b0103862600001a05349849c2e518854b0b7016d00e27408e02560823a1910105003b290090cd00a02034a553f2cc80809d7141220a204006194281ff1088d7504300b88140044241400d2147ab06a00d080a5c885c14212c645250ce480320c346a2c2c0e204e796a8487339332829d0c22105470a0a8b031f9161124d40d05400003084246088d8c009a0420c6204ca48ac1c4559a18471c34e6b8e1108213d53010e22144a000c3850ac9c8c450f0c655c23d0a801804c888125784c2804265",
  miner: "0x5a0b54d5dc17e0aadc383d2db43b0a0d3e029c4c",
  mixHash: "0x2c08ca89b804f373aefb8157afc12a4e44df58a53719e1a05564d62867be2fac",
  nonce: "0x228a1e700639d330",
 //....其他信息省略....

  • 交易的收据信息, 收据中的logsBloom只是当前交易的logs中的address 和 topic所决定

    
    > eth.getTransactionReceipt("0x866e638469e8ac0a50919254ed5191994f184358e380c9b9ea48e11a4a3a7d89")
    {
      blockHash: "0x6eabf54758b981adf0736ec5521593199b64d1af668120eacb9dea665c85a5f9",
      blockNumber: 8348692,
      contractAddress: null,
      cumulativeGasUsed: 7415262,
      from: "0xe29377ae332f422211dcfbd3ca0352d83e26dd47",
      gasUsed: 53246,
      logs: [{
          address: "0x1fcdce58959f536621d76f5b7ffb955baa5a672f",
          blockHash: "0x6eabf54758b981adf0736ec5521593199b64d1af668120eacb9dea665c85a5f9",
          blockNumber: 8348692,
          data: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
          logIndex: 125,
          removed: false,
          topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000e29377ae332f422211dcfbd3ca0352d83e26dd47", "0x00000000000000000000000033019e5f5e2340f12bd3da326b89ec65e7770869"],
          transactionHash: "0x866e638469e8ac0a50919254ed5191994f184358e380c9b9ea48e11a4a3a7d89",
          transactionIndex: 170
      }],
      logsBloom: "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000010000000000000000000000000000000000000000000000000000200000000000000000000200000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000080000000000000002020000000000000000000000000000000000000000000000000000000000000000000000001",
      status: "0x1",
      to: "0x1fcdce58959f536621d76f5b7ffb955baa5a672f",
      transactionHash: "0x866e638469e8ac0a50919254ed5191994f184358e380c9b9ea48e11a4a3a7d89",
      transactionIndex: 170
    }
    
    
  • pyethereum的源码

class Log(rlp.Serializable):

    # TODO: original version used zpad (here replaced by int32.serialize); had
    # comment "why zpad"?
    fields = [
        ('address', utils.address),
        ('topics', CountableList(utils.int32)),
        ('data', binary)
    ]

    def __init__(self, address, topics, data):
        if len(address) == 40:
            address = decode_hex(address)
        assert len(address) == 20
        super(Log, self).__init__(address, topics, data)

    def bloomables(self):
        return [self.address] + [utils.int32.serialize(x) for x in self.topics]

    def to_dict(self):
        return {
            "bloom": encode_hex(bloom.b64(bloom.bloom_from_list(self.bloomables()))),
            "address": encode_hex(self.address),
            "data": b'0x' + encode_hex(self.data),
            "topics": [encode_hex(utils.int32.serialize(t))
                       for t in self.topics]
        }

    def __repr__(self):
        return '<Log(address=%r, topics=%r, data=%r)>' %  \
            (encode_hex(self.address), self.topics, self.data)
  • 使用ethereum生成logsBloom进行比对

    
    >>> from ethereum.messages import *
    >>> 
    >>> log = Log(address='1fcdce58959f536621d76f5b7ffb955baa5a672f', topics=[0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000e29377ae332f422211dcfbd3ca0352d83e26dd47, 0x00000000000000000000000033019e5f5e2340f12bd3da326b89ec65e7770869], data='0000000000000000000000000000000000000000000000000de0b6b3a7640000'.decode('hex'))
    >>> 
    >>> log.to_dict()
    {'data': '0x0000000000000000000000000000000000000000000000000de0b6b3a7640000', 'topics': ['ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', '000000000000000000000000e29377ae332f422211dcfbd3ca0352d83e26dd47', '00000000000000000000000033019e5f5e2340f12bd3da326b89ec65e7770869'], 'bloom': '00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000010000000000000000000000000000000000000000000000000000200000000000000000000200000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000080000000000000002020000000000000000000000000000000000000000000000000000000000000000000000001', 'address': '1fcdce58959f536621d76f5b7ffb955baa5a672f'}
    >>> 
    >>> 
    >>> log.bloomables()
    ['\x1f\xcd\xceX\x95\x9fSf!\xd7o[\x7f\xfb\x95[\xaaZg/', '\xdd\xf2R\xad\x1b\xe2\xc8\x9bi\xc2\xb0h\xfc7\x8d\xaa\x95+\xa7\xf1c\xc4\xa1\x16(\xf5ZM\xf5#\xb3\xef', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2\x93w\xae3/B"\x11\xdc\xfb\xd3\xca\x03R\xd8>&\xddG', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x01\x9e_^#@\xf1+\xd3\xda2k\x89\xece\xe7w\x08i']
    >>> 
    >>> bx = 0xd82011ccca1160c828c342000bcad811448c8290041c342a08c284a8001c106e601401400889090808965c029248094602600e8e0bc0149f03b001ce0039a8b0103862600001a05349849c2e518854b0b7016d00e27408e02560823a1910105003b290090cd00a02034a553f2cc80809d7141220a204006194281ff1088d7504300b88140044241400d2147ab06a00d080a5c885c14212c645250ce480320c346a2c2c0e204e796a8487339332829d0c22105470a0a8b031f9161124d40d05400003084246088d8c009a0420c6204ca48ac1c4559a18471c34e6b8e1108213d53010e22144a000c3850ac9c8c450f0c655c23d0a801804c888125784c2804265
    >>> 
    >>> 
    >>> //判断某个事件(ERC20的keccak256(transfer(from,to,value)) )是否在此区块中
    >>> bloom_query(bx, 'ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'.decode('hex'))
    True
    >>> 
    >>>  //查看某个地址是否在此区块中, 注意地址 不要'0x'前缀
    >>> bloom_query(bx, '1fcdce58959f536621d76f5b7ffb955baa5a672f'.decode('hex'))
    True
    >>> 
    
  • 分析失败的合约执行是否可以用logsBloom过滤

https://etherscan.io/tx/0x516fd3e91718d5576f4d1b9dc4de6ef9f597615675e69705f90d88b64d4b4fe2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEvliFuH-1620963035689)(./img/erc20_failed.png)]


> eth.getBlockByNumber("0x802e65", false)
{
  difficulty: "0x7e4b2262a729f",
  extraData: "0x505059452d65746865726d696e652d6575312d37",
  gasLimit: "0x7a2135",
  gasUsed: "0x7a156d",
  hash: "0xb84959b878c9e6a753637d0d8ded53fc3e404dd763cbc85351e1bf60c35cd2f4",
  logsBloom: "0x040e14c44940903a951a060d0311308f80408c11876cd83d141983460a42111a8e40004820581411b8a803024a1c8142044956101862a893020047380030f03ae564892be0024abe451a758849f8c8a88728650002c24143219160d894024409482018028b60a60006842670e4001c4107931214226a439a195069177022e0c702400b04804a940d118ec411801609e68240fc2d401a951d6049b110e150c9a212505c851e264028101146840806186620122700b80bf04145522020bdbd6a322610d07600440369091c2010ad0304050a5558552010421e2b801a50944ba928d311c5153612518860830412944820849610bc4007d4a4e80a253251418502c5",
  miner: "0xea674fdde714fd979de3edf0f56aa9716b898ec8",
  mixHash: "0x18e5df8b0941134b4a02f33679400ee52d6e8ebe7a22076c173ad63ee0f398ef",
  nonce: "0x1d6b49c20db8d89a",
  number: "0x802e65",
.....其他省略.....

>>> bx = 0x040e14c44940903a951a060d0311308f80408c11876cd83d141983460a42111a8e40004820581411b8a803024a1c8142044956101862a893020047380030f03ae564892be0024abe451a758849f8c8a88728650002c24143219160d894024409482018028b60a60006842670e4001c4107931214226a439a195069177022e0c702400b04804a940d118ec411801609e68240fc2d401a951d6049b110e150c9a212505c851e264028101146840806186620122700b80bf04145522020bdbd6a322610d07600440369091c2010ad0304050a5558552010421e2b801a50944ba928d311c5153612518860830412944820849610bc4007d4a4e80a253251418502c5
>>> 
>>> bloom_query(bx, 'cfe4b035f17209df73198bed33793718b277981b'.decode('hex'))
False

  • 分析结论
    • 普通的ETH转账是没有log的
    • 只有成功执行完的合约才会生成log, 失败的不会生成log
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ERC20代币合约中的`toggle`函数是用于切换是否需要签名的函数。如果该函数被调用,那么代币转移交易就不需要经过用户的签名确认,而是直接由智能合约执行。这种方式可以用于一些特殊场景,比如允许信任的第三方执行代币转移交易,或者在某些情况下需要快速执行代币转移交易等。 使用Toggle函数需要满足以下条件: 1. 合约的owner需要调用该函数进行切换。 2. 调用该函数需要提供owner的签名,以验证调用者的身份。 使用web3.js调用Toggle函数的示例代码如下: ``` // 假设以下变量已经定义并初始化 // ERC20代币合约的地址 var tokenAddress = "0x1234567890123456789012345678901234567890"; // 合约owner的地址和私钥 var ownerAddress = "0x1122334455667788990011223344556677889900"; var ownerPrivateKey = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; // web3.js provider var web3Provider = new Web3.providers.HttpProvider("http://localhost:8545"); // 实例化web3.js对象 var web3 = new Web3(web3Provider); // 实例化ERC20代币合约 var tokenContract = new web3.eth.Contract(tokenAbi, tokenAddress); // 调用Toggle函数 function toggleSign() { // 判断是否为owner tokenContract.methods.owner().call().then(function (result) { if (result === ownerAddress) { // 构造toggle函数的参数 var data = tokenContract.methods.toggle().encodeABI(); // 对参数进行签名 var hash = web3.utils.soliditySha3({type: 'address', value: tokenAddress}, {type: 'bytes', value: data}); var sig = web3.eth.accounts.sign(hash, ownerPrivateKey); // 构造调用参数 var payload = '0x' + data.substring(2) + sig.r.substring(2) + sig.s.substring(2) + sig.v.toString(16); // 调用ERC20代币合约的方法 tokenContract.methods.toggle().send({from: ownerAddress, data: payload}).then(function (result) { console.log(result); }).catch(function (err) { console.error(err); }); } else { console.error("Not owner"); } }).catch(function (err) { console.error(err); }); } ``` 在上述示例中,我们首先实例化了web3.js对象和ERC20代币合约,然后定义了一个toggleSign函数,用于调用Toggle函数。在toggleSign函数中,我们首先通过调用owner函数,判断调用者是否为owner。然后,我们构造Toggle函数的参数,并对参数进行签名。最后,我们将签名后的参数和Toggle函数的selector合并,构造调用参数,然后调用ERC20代币合约的方法。在调用Toggle函数时,如果签名验证通过,那么代币转移交易就可以不需要经过用户的签名确认,直接由智能合约执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值