关于区块链:鲜衣怒马散尽千金Vue30Tornado6前后端分离集成Web30之Metamask钱包区块链虚拟货币三方支付功能

4次阅读

共计 7485 个字符,预计需要花费 19 分钟才能阅读完成。

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_219

不得不抵赖,大多数人并不领有或者已经领有加密货币。是的,Web3.0、加密货币、区块链,对于大多数的互联网用户来说,其实是一些过于轻佻的词汇。如果你是为了谋求暴利投机而钻研区块链和加密货币,那你多半会悲观,因为盐在哪里都是咸的;而如果你是为了解脱常识枷锁而学习区块链,那你简直肯定能满足,因为糊涂决不是编程界的常态。

对于领取零碎来说,加密货币的次要益处之一是去中心化,这意味着它由许多团队或个人管制和治理,而不是一个繁多的中心化机构,暗箱操作在这里并不存在,这为零碎带来了透明度。加密货币的另一个益处是它是一个点对点零碎,因为它能够发送给世界上任何人,打消了微信、支付宝等第三方领取寡头的干涉,这使得它们具备老本效益。

本次,就让咱们来为领取零碎添上加密货币领取的这一笔,通过 Vue3.0+Tornado6 的前后端拆散零碎,一睹区块链加持上来中心化领取逻辑的风采。

后期筹备

首先,咱们当然须要一个加密货币钱包,对于系统集成 MetaMask 钱包的逻辑,请参见之前的一篇:青山不遮,毕竟东流,集成 Web3.0 身份钱包 MetaMask 以太坊一键登录 (Tornado6+Vue.js3)。

其后,咱们须要为接下来的领取行为支付一些“测试加密货币”,支付测试币的网站被称为水龙头(faucet),测试币被称为水,所以支付测试币的过程也被叫做领水。

咱们以 Rinkeby 的测试币支付为例解说过程,其余测试网的测试币支付形式相似,如果违心,大家能够把几个测试网的水都领一些。

第一步,关上钱包插件,抉择一个钱包,点击设置:

随后,抉择高级,而后启用测试网络:

接着,将网络切换到 Rinkeby 测试网络,网络中还能够看到 Ropsten、Kovan 和 Goerli 等其余三个测试网络,四个测试网络各有特点,Ropsten 采纳 POW 机制,能够本人搭建节点挖测试币,然而稳定性较差,偶然还会遇到区块回滚的状况,很多实验性测试,比方“区块阻塞攻打”试验会放到这个测试网来测试;Kovan、Rinkeby 和 Goerli 是采纳 POA 机制,这几个测试网络不能通过挖矿的形式获取测试币,只能通过水龙头支付,咱们以 Rinkeby 为例解说支付过程,Kovan 和 Goerli 相似,但支付条件更为严格,大家能够依据须要支付。

切换好 Rinkeby 测试网络后,拜访水龙头网站:https://faucets.chain.link/ri… 通过钱包进行链接登录,而后将钱包地址填入支付表单,即可支付 0.1 的 eth 货币:

支付交易确认之后,查看钱包余额:

至此,后期筹备工作就实现了。

钱包领取加签

前端在 Vue3.0 我的项目中装置区块链模块和异步申请模块:

npm install --save ethers

npm install --save axios

随后在组件中导入区块链模块:

import {ethers} from 'ethers';

并且对 axios 进行简略封装:

const myaxios = function(url,type,data={}){  
  
    return new  
  
    Promise((resolve) => {  
  
  
        // 判断  
        if(type==="get" || type === "delete"){  
  
  
            axios({  
  
                method:type,  
                url:url,  
                params:data  
            }).then((result) => {resolve(result.data);  
  
            });  
  
  
        }else{  
  
  
            axios({  
  
                method:type,  
                url:url,  
                data:qs.stringify(data)  
            }).then((result) => {resolve(result.data);  
  
            });  
  
  
  
        }  
  
  
    });  
  
  
  
}  
  
const app = createApp(App)  
app.config.globalProperties.myaxios = myaxios;

接着,当页面首次加载时,咱们心愿检查用户是否曾经将钱包连贯到站点。为此,咱们须要应用 eth\_accounts 办法获取用户的帐户。如果没有返回帐户,这意味着用户没有连贯:

checkIfWalletConnected:function() {window.ethereum.request({ method: 'eth_accounts'}).then(function (accounts) {if (accounts.length > 0) {console.log(accounts[0]);  
  
        } else {alert("利用未链接钱包");  
        }  
  
    });  
}

随后,在初始化办法内对以后用户进行检测:

created(){this.checkIfWalletConnected();  
  
  
  }

如果用户钱包链接没问题,那么构建领取表单:

<input type="text" v-model="amount" />  
  
<a-button type="primary" @click="create_sign"> 点击领取 </a-button>

这里用户点击领取按钮后,进入加签逻辑:

create_sign:function(){var provider = new ethers.providers.Web3Provider(web3.currentProvider);  
  
        // 获取签名对象  
        var signer = provider.getSigner();  
  
        // 工夫戳  
        var rightnow = (Date.now()/1000).toFixed(0);  
  
        var sortanow = rightnow - (rightnow % 600);  
  
        // 生成签名  
        signer.signMessage("Trade with"+document.domain+"at"+sortanow+"for"+this.amount,this.accountaddress,"test").then((signature) => {this.check_sign(signature);  
  
  
        });  
  
    }

这里通过 Web3Provider 获取到签名实例,随后依据工夫戳 + 域名 + 领取金额生成签名,签名生成后,立即调用 check\_sign 办法向后盾发动异步申请进行验签操作:

check_sign:function(signature){this.myaxios(this.weburl+"/sign/","post",{"signature":signature,"accountaddress":this.accountaddress,"amount":this.amount}).then(data =>{if(data.errcode == 0){this.makePaymentRequest(data.data.selleraddress,data.data.amount);  
                
              }  
  
  
        });  
  
  
    }

这里将签名和钱包地址发送给后端,在客户端与钱包申请交互的过程中,申请的数据很容易被拦挡并篡改,所以加签环节必不可少:

后端验签并创立交易

后端须要 web3 模块的加持:

pip3 install web3

随后创立验签办法:

from web3.auto import w3  
# 反编译办法  
from eth_account.messages import defunct_hash_message  
import time  
  
class CheckSign(BaseHandler):  
  
  
    async def post(self):  
  
        signature = self.get_argument("signature",None)  
  
        accountaddress = self.get_argument("accountaddress",None)  
  
        amount = self.get_argument("amount",None)  
  
        selleraddress = "0x95f57Bf3837325FE99a611EFacff6b1d70C7731A"  
  
  
        # 获取以后域名  
        domain = self.request.host  
  
        if ":" in domain:  
  
            domain = domain[0:domain.index(":")]  
  
        # 工夫戳  
        now = int(time.time())  
  
        sortanow = now - now % 600  
  
        # 生成签名  
        message = "Trade with {} at {} for {}".format(domain,sortanow,amount)  
  
        print(message)  
  
        # 反编译  
        message_hash = defunct_hash_message(text=message)  
  
        # 获取签名对象  
        signer = w3.eth.account.recoverHash(message_hash,signature=signature)  
  
        print(accountaddress,signer)  
  
        if accountaddress == signer.lower():  
  
            res = {"errcode":0,"msg":"ok","data":{"selleraddress":selleraddress,"amount":str(w3.toWei(amount,'ether'))}}  
  
        else:  
  
            res = {"errcode":1,"msg":"failed"}  
  
        self.finish(res)

这里后端通过同样的算法对签名进行验证,如果验签通过,后端将会返回商户的钱包地址,也就是用户转账的钱包地址,同时会将付款金额通过 w3.toWei 办法进行转换,以太币的最小单位为 wei,1 个以太币相当于 10 的 8 次方 wei。通常,大家也应用 Gwei 作为展现单位。比拟罕用的就是 eth,Gwei 和 wei。

但为了统一标准,领取表单汇总显示的是 eth 最大单位,所以通过 toWei 办法,将最大单位转换为最小单位,即 0.001eth=100000000000000wei,留神转换后须要以字符串的模式返回到前端。

随后后端将商户钱包地址和转换后的领取金额返回给前端。

创立交易

回到前端,验签通过后,前端获取领取钱包地址和金额,旋即通过钱包创立领取:

makePaymentRequest:function(sellerAddress,amount) {window.ethereum.request({ method:'eth_sendTransaction', params: [{ from:this.accountaddress, to:sellerAddress,value:amount}] })  
    .then(response => {console.log("交易号:"+response);  
        var orderid = response;  
    })  
    .catch(error => {console.log(error);  
    });  
  
}

通过 eth\_sendTransaction 办法发动交易,当用户批准领取申请时,将会返回此笔交易的 TransactionHash,也就是交易哈希号:

确认领取交易后,获取 TransactionHash:

 交易号:0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26 

事实上,每一笔领取交易都会产生另一笔“燃料费”,交易燃料费将归属于挖出区跨链中本次交易区块的矿工。当矿工挖矿时,他须要决定哪些交易放入到区块中,能够随机抉择交易,也能够不蕴含任何交易。为了激励让矿工将你的交易放入区块,相应地,你必须付出一部分“小费”。

领取查问

领取确认之后,咱们能够利用 Rinkeby 网络站点通过输出交易哈希号来查问这一笔交易:https://rinkeby.etherscan.io/…:

当然了,让用户本人在“水龙头”上查问领取后果显然不怎么考究,后端必定须要记录交易哈希号并且查问交易明细,这里咱们须要一个“上链”服务,让咱们的后端也接上区块链网络,拜访 https://infura.io/

Infura 是一种 IaaS 产品,目标是为了升高拜访以太坊数据的门槛。对于开发者来说,Infura 是一个能够让你的 dApp 疾速接入以太坊的平台,不须要本地运行以太坊节点。Infura 背地是负载平衡的 API 节点集群。有针对以太坊 Infura 有一系列的开发套件。

注册后,创立链接我的项目:

随后,复制 Rinkeby 节点链接:

接着,创立订单查问脚本 checkorder.py:

from web3 import Web3  
w3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/32ff12c27a9c485db9a7b61b0a7f3f61"))  
  
print(w3.isConnected())  
  
print(w3.eth.getTransactionReceipt("0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26"))

这里一旦“上链”胜利,就能够依据交易哈希号来查问交易的明细,零碎返回:

True  
AttributeDict({'blockHash': HexBytes('0x4ede42c4bd15c7ce1736523ae1f84284c7bbdc17388cfbae0df2897bf19f287c'), 'blockNumber': 11098045, 'contractAddress': None, 'cumulativeGasUsed': 13409523, 'effectiveGasPrice': 1500000017, 'from': '0x3B14DdBa7FFF887ED3CCF01fCa0b84501Fd7a711', 'gasUsed': 21000, 'logs': [], 'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'), 'status': 1, 'to': '0x95f57Bf3837325FE99a611EFacff6b1d70C7731A', 'transactionHash': HexBytes('0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26'), 'transactionIndex': 16, 'type': '0x2'})

至此,实现的加密货币领取逻辑就实现了,大体流程如下:

1. 利用会载入并主动查看 Metamask 钱包是否已连贯。如果没有,将会提醒用户装置钱包插件并且链接。
2. 交易加签操作。

3. 后端验签,并且返回商户钱包地址以及转换金额。

4. 钱包创立交易。

5. 用户审核并确认付款。
6. 用户确认交易,生成交易号,用户和利用都会收到付款确认。

退款

很遗憾,用户在向钱包地址发送加密货币时必须十分小心,如果有人将加密货币发送到任何谬误的地址,用户将无奈勾销交易或提出任何投诉以取得退款,是的,deal is deal,当交易行为曾经被写入区块,那么是无奈被撤销的。

但这并不象征的用户就会因而和平台商户产生纠纷,如果沟通之后,达成了退款协定,加密货币也能够间接从后盾进行转账操作:

from web3 import Web3  
import os  
  
w3 = Web3(Web3.HTTPProvider("https://rinkeby.infura.io/v3/32ff12c27a9c485db9a7b61b0a7f3f61"))  
  
print(w3.isConnected())  
  
address1 = w3.toChecksumAddress('selleraddress')  
address2 = w3.toChecksumAddress ('accountaddress')  
private_key = os.getenv('PRIVATE_KEY')  
# in this case, the nonce is the amount of transactions on accounti  
nonce = w3.eth.getTransactionCount(address1)  
# setup the transaction  
tx ={  
'nonce':nonce,  
"to":address2,  
'value':w3.toWei("0.0001","ether"),  
"gas": 21000,  
"gasPrice":w3.toWei(40,'gwei'),  
}  
signed_tx = w3.eth.account.signTransaction(tx, private_key)  
  
tx_hash = w3.sendRawTransaction(signed_tx.rawTransaction)

这里商户只须要将钱包私钥导入环境变量,随后创立交易并通过私钥加签,最初确认交易,并且获取到交易哈希号。

结语

毫无疑问,加密货币会侵害一部分传统行业既得利益者的利益,但也不能不抵赖,加密货币更是二十一世纪的一记响雷,就像洪荒时代孑余的一头恐龙、大戈壁中枝叶扶疏的一株胡杨、兵马俑阵中一个脉搏跳动体温犹存的肉身、死寂的山谷中凭空乍响的一声洪钟。所谓衣不如新,人不如故,不入春园,怎知秋色几许?所谓技术的实质就是最大额度地播种翻新,你批准吗?

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_219

正文完
 0