用户充币 -- > 钱进入分配地址 --> 分配地址转入主钱包 --> 用户提币 --> 从主钱包直接转入用户提币地址
(如果采用冷热钱包配合,只需将百分之二十资金留在热钱包便可供日常提币) 具体的架构设计应根据业务来判断,有些钱包的做法是 用户充的币留在原钱包里
转账进主钱包的时候 以太币可以 采用 (用户转入金额除开手续费全部转入中心钱包),但是更推荐的做法是 用户第一次注册时 为用户钱包转入一定的手续费
步骤:
1. 安装go-ethereum,给每个用户生成一个以太坊钱包地址;
2. 用户会把ETH充值到这个钱包;
3. 监听以太坊钱包的转账记录,并同步到用户账号余额;
通过etherscan的api监听全部transaction,接口是
url = "http://api.etherscan.io/api?module=account&action=txlist&address=#{address}&startblock=0&endblock=99999999&sort=desc&apikey=#{API_KEY}"
然后通过判断返回每个transaction的to字段是否等于address,来判断这条记录是否为转入记录,confirmations来判断确认数,通常大于12个确认数就可以了,isError来判断这条记录是否转账异常,再判断数据库是否已经存在这条记录,如果不存在,就存进数据库,并在用户余额上加上这个数字。
4. 监听钱包余额,把充值进来的币集中转入热钱包;
区别在于交易所是如何把充值进来的币集中到一个热钱包里,有的交易所会按照上一篇所说的那样,跑定时任务去转账,另一种比较有意思的就是用智能合约去转账,也就是服务器生成钱包的那一步,其实是部署了一个智能合约,合约里写好逻辑,币转进来就会被合约自动转账给热钱包,目前我实现的方法是第一种。
第一版实现,因为服务器资源有限,业务也是刚起步,就没浪费资源去自己运行以太坊节点,使用了infura.io的json rpc节点,好处是不需要担心维护以太坊节点,暂时可以相信这个节点是不会坏掉的,坏处就是以太坊json rpc的节点是不支持根据钱包地址查询全部转账记录的,所以第一版用了比较hack的手段监听余额数字。
同样是定时脚本,监听余额,发现有余额大于0的钱包地址,就把钱包里的钱转入热钱包,并在对应用户的余额上加对应的数字。这样做会出问题,一开始的想法是,每次监听都把钱包里的余额全都转到热钱包,这样保证钱包里的余额永远是0,每次充值都是加上钱包里的余额就好,这样做的前提是,要把gasLimit设置成21000,转账amount为钱包里的余额减去gas费用,但是这笔转账很容易因为gas不足就失败了,为了保证每笔转账能尽可能成功,要把gasLimit设置的大一点,这样做就会导致没用完的gas会返还给钱包,钱包里的余额就不再是0,所以又加了一段hack的代码,每次监听都会把余额的数字缓存起来,并且每次监听,如果监听到的余额小于这个缓存,就缓存这个小的数字,而逻辑上钱包里的余额是,以太坊钱包真实余额减去这个缓存的数字,这样做一看就漏洞百出,但是在充值频率正常的情况下,是work了。进度原因,用这种心惊肉跳的逻辑运行了很长一段时间。
第二版,就是用etherscan的api,拿到钱包地址的转账记录,提出转入的记录,写进数据库,不会同步进行链上转账,每天跑一次集中到热钱包的脚本就够了,这样的好处是不会出现充值出错的问题,逻辑也比较清晰,不需要hack,可能的坏处就是,etherscan挂掉了,我们的服务也就不能用了,可能etherscan坏掉的概率和infura坏掉的概率差不多吧。我想最好的解决办法就是自己运行一个以太坊节点吧,做etherscan相同的事儿,就能自己监控记录了,这就不会让自己的服务依赖别人的东西了。