0%

比特币地址和私钥与以太坊的异同

比特币的地址和私钥的关系和以太坊也是一样的,参见以太坊(eth)简介

但是在显示上有一些区别

  • 比特币的地址用的是Base58的序列化显示方式,这个方式是大小写敏感的,所以要注意比特币的地址是不能转化大小写的。
  • 比特币的私钥导出时一般使用WIF格式,为了给私钥加验证,比特币的私钥导出时在首位会加一个netID。这个netID对应不同的网络,例如比特币测试网络,比特币正式网络,莱特币等等;而在末尾会加一个数据校验,用来验证数据是否被损坏。
阅读全文 »

比特币记账方式

比特币和以太坊一样,也是一个账本。不过比特币和以太坊的记账方式差别还是很大的。

以太坊的记账方式是余额,余额以地址一一对应。

比特币的记账方式为UTXO(Unspent Transaction Output),翻译出来大概是未消费交易输出。而地址的余额就是该地址所剩余的所有的UTXO金额的总和。

阅读全文 »

数据结构的一些说明

erc20的提币和eth的提币处理方式基本相同,只是生成交易数据的逻辑有些区别。但是我们要注意一种情况,就是多个erc20的代币热钱包可能是相同的,这样我们在查询代币热钱包余额的时候需要查询不同代币的余额。

比如代币表数据为

代币id 代币合约地址 代币单位 热钱包地址
1 0xA usdt 0x1
2 0xB tcp 0x1
3 0xC pc 0x1

提币数据为

提币id 代币单位 提币地址 提币金额
1 usdt 0x2 0.11
2 tcp 0x3 1.23
3 pc 0x4 9.8

所以我们获取热钱包0x1的代币余额的时候需要生成类似这样一个map, map[热钱包地址-代币id] = 热钱包余额的结构

阅读全文 »

erc20 简介

erc20代币实际上就是实现了erc20接口的eth合约。例如我们常见的币种都实现了erc20的接口,例如

  • Tether USD (USDT)
  • BNB (BNB)
  • HuobiToken (HT)
  • OKB (OKB)

erc20的接口代码是这样的

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
pragma solidity ^0.4.24;

contract ERC20 {
// 合约名 例如 Tether USD
string public constant name = "";
// 单位名 例如 USDT
string public constant symbol = "";
// 小数点后位数 例如 6
uint8 public constant decimals = 0;

// 代币总数额
function totalSupply() public constant returns (uint);
// 返回某个地址tokenOwner的代币数额
function balanceOf(address tokenOwner) public constant returns (uint balance);
// 返回地址address允许地址tokenOwner提取的代币数额
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
// 将调用者的tokens数额的代币转账给地址to
function transfer(address to, uint tokens) public returns (bool success);
// 允许调用者的tokens数额代币共地址spender提取
function approve(address spender, uint tokens) public returns (bool success);
// 从地址from中转账tokens数额的代币给地址to
function transferFrom(address from, address to, uint tokens) public returns (bool success);
// 发生代币转账时候的通知,存放于log中
event Transfer(address indexed from, address indexed to, uint tokens);
// 发生允许他人提取自己的代币时候的通知,存放于log中
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
阅读全文 »

回调时序图大概如下

当用户冲币和提币的时候,我们需要把这些信息通知用户。这个通知我们也是通过http调用实现,只不过我们调用的是product中提供的回调地址。

比如用户冲币的时候,我们回调的内容是:

1
2
3
4
5
6
7
8
9
{
"address":"0xa94ae9cd4d3ad8a29697da180bda45040e633501",
"app_name":"app_1",
"balance":"0.0001",
"notify_type":1,
"sign":"97E589CEC28A80CD9FBCE0F042C08837",
"symbol":"eth",
"tx_hash":"0xd1fe86cc358f525e452cbab251adc403b531da230304e71887fda911a40e8286"
}

这里我们用相同的逻辑签名获得sign一同返回,因为tx_hash每笔交易都不相同,可以作为nonce使用。

阅读全文 »

提币的总体时序图大概是这样的:

<以太坊(eth)交易所钱包开发 - 5 - 获取冲币地址>中已经介绍了API请求数据的验证方式,这部分验证都是一样的,用gin的自定义的中间件完成就可以了。

提币请求的参数为:

1
2
3
4
5
6
var req struct {
Symbol string `json:"symbol" binding:"required" validate:"oneof=eth"`
OutSerial string `json:"out_serial" binding:"required" validate:"max=40"`
Address string `json:"address" binding:"required"`
Balance string `json:"balance" binding:"required"`
}

我们需要注意OutSerial字段,这个字段是为了避免同一提币请求被多次处理添加的,数据库会给这个字段做一个唯一索引,相同的提币便无法被重复插入了。

阅读全文 »

验证请求是否合法

基础功能完成以后我们需要为外部提供服务了。这里我们对外提供RestFul API,使用gin来做http server。因为涉及到资产,所以我们需要对请求数据做一些验证,主要字段如需下:

1
2
3
4
5
var req struct {
AppName string `json:"app_name" binding:"required"`
Nonce string `json:"nonce" binding:"required" validate:"max=40"`
Sign string `json:"sign" binding:"required"`
}

在数据库中,我们同样需要添加一个产品表,用来对应请求中的AppName字段。

1
2
3
4
5
6
7
8
9
CREATE TABLE `t_product` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`app_name` varchar(128) NOT NULL DEFAULT '' COMMENT '应用名',
`app_sk` varchar(64) NOT NULL DEFAULT '' COMMENT '应用私钥',
`cb_url` varchar(512) NOT NULL COMMENT '回调地址',
`whitelist_ip` varchar(1024) NOT NULL DEFAULT '' COMMENT 'ip白名单',
PRIMARY KEY (`id`),
UNIQUE KEY `app_name` (`app_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
阅读全文 »