最近几年区块链技术的使用外延持续扩展,去中心化的节点认证机制可以大幅度改进传统的支付结算模式的经营效率,降低交易者的成本并提高收益。但不能否认的是,区块链技术也存在着极大的风险,所谓身怀利器,杀心自起,业内应当谨慎使用与推广区块链技术。

本次,就让我们来为支付系统添上区块链支付功能,通过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/rinkeby 通过钱包进行链接登录,然后将钱包地址填入领取表单,即可领取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/tx/0xe937c66e337322cf3b83788b495af2da35ff9635aaaa20f156c74c7f7fddad26:

当然了,让用户自己在“水龙头”上查询支付结果显然不怎么讲究,后端肯定需要记录交易哈希号并且查询交易明细,这里我们需要一个“上链”服务,让我们的后端也接上区块链网络,访问 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)

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

结语

区块链技术是二十一世纪的一记响雷,就像洪荒时代孑余的一头恐龙、大戈壁中枝叶扶疏的一株胡杨、兵马俑阵中一个脉搏跳动体温犹存的肉身、死寂的山谷中凭空乍响的一声洪钟。所谓衣不如新,人不如故,不入春园,怎知春色几许?所谓技术的本质就是最大额度地收获创新,你同意吗?

区块相隔虽一线,俱在支付同冶熔,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask区块链虚拟三方支付功能的更多相关文章

  1. 鲜衣怒马散尽千金,Vue3.0+Tornado6前后端分离集成Web3.0之Metamask钱包区块链虚拟货币三方支付功能

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_219 不得不承认,大多数人并不拥有或者曾经拥有加密货币.是的,Web3.0.加密货币.区块链,对于大多数的互联网用户来说,其实是一 ...

  2. 一行代码实现Vue微信支付,无需引用wexin-sdk库,前后端分离HTML微信支付,无需引用任何库

    前后端分离项目实现微信支付的流程: 1:用户点击支付 2:请求服务端获取支付参数 3:客户端通过JS调起微信支付(微信打开的网页) * 本文主要解决的是第3步,视为前两步已经完成,能正确拿到支付参数, ...

  3. Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_182 之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内 ...

  4. 前后端分离djangorestframework—— 接入支付宝支付平台

    支付宝 简介 支付宝是什么不用多说了,本次教程适合初学者 前提准备 话不多说,干就完了 1.注册开发者账号,设置公钥私钥 首先进入支付宝开发者平台:传送门 ,有账号直接登录,没账号用你平时用来付款收钱 ...

  5. lf 前后端分离 (6) 支付

    支付 import datetime from django.core.exceptions import ObjectDoesNotExist from rest_framework.views i ...

  6. 小程序php支付,前后端分离

    小程序端: xml: <button type="default" bindtap="payOrder">支付</button> js: ...

  7. web3.0、比特币、区块链、元宇宙,以及那些待收割的韭菜们!

    前几天看到周星驰在社交账号上招聘web3.0的人才,感觉有必要说说web3.0,当然不是基于技术层面,而是从另一个维度说说web3.0以及其它相关的概念,从而做到如何反欺诈,如何避免被资本割韭菜.想到 ...

  8. 应用内支付(IAP)可加入三方支付

    Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付   Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付S ...

  9. Windows Phone 放开政策 - 应用内支付(IAP)可加入三方支付

    Windows Phone 应用商店在 今年(2013)11月04号 修改了商店政策 允许公司账户的应用使用三方支付SDK. 通过 App certification requirements cha ...

随机推荐

  1. nginx https证书配置

    1. Nginx配置 server { listen 443; #指定ssl监听端口 server_name www.example.com; ssl on; #开启ssl支持 ssl_certifi ...

  2. BUUCTF-秘密文件

    秘密文件 根据提示得知是属于文件被下载了,查看了下流量包直接过滤ftp包 这里看到有个RAR包存在,应该是隐写了 使用foremost分离即可 得到压缩包存在密码 默认四位纯数字爆破即可 flag{d ...

  3. SAP Tree

    Effect picture Code as bellow *&---------------------------------------------------------------- ...

  4. iNeuOS工业互联网操作系统,视图建模(WEB组态)增加2154个行业矢量图元、大屏背景及相关图元

     1.   概述 现在三维数字孪生(3D)比较流行,各行业各领域的项目也都在上数字孪生项目或是项目中包括数字孪生模块,能做的厂家也很多.从全厂区的应用视觉的冲击力还是比较震撼,但是数字孪生不太可能包括 ...

  5. Servlet 体系结构

    Servlet体系结构 Servlet -- 接口 Genericservlet -- 抽象类 继承类接口 实现了空方法  只需要复写service方法 HttpServlet -- 抽象类  对Ht ...

  6. 如何通过WinDbg获取方法参数值

    引入 我们在调试的过程中,经常会通过查看方法的输入与输出来确定这个方法是否异常.那么我们要怎么通过 WinDbg 来获取方法的参数值呢? WinDbg 中主要包含三种命令:标准命令.元命令(以 . 开 ...

  7. 【MAUI】为 Label、Image 等控件添加点击事件

    一.前言 已经习惯了 WPF.WinForm 中"万物皆可点击"的方式. 但是在 MAUI 中却不行了. 在 MAUI 中,点击.双击的效果,是需要通过"手势识别器&qu ...

  8. labview从入门到出家4--用事件结构实现运算功能

    使用事件结构可以快速定位响应界面的操作事件,如按下,拖动,双击的事件.基本上我们所要实现的所有功能,都可以通过条件结构+事件结构去实现,比如后面进阶篇将会讲到的状态机就是通过条件结构和事件结构组成的. ...

  9. Solution -「树状数组」 题目集合

    T1 冒泡排序 题目描述 clj 想起当年自己刚学冒泡排序时的经历,不禁思绪万千 当年,clj 的冒泡排序(伪)代码是这样的: flag=false while (not flag): flag=tr ...

  10. 常用的函数式接口_Predicate接口_默认方法and和Predicate接口练习_集合接口筛选

    默认方法:and 既然是条件判断,就会存在与.或.非三种常见的逻辑关系.其中将两个Preadicate条件使用"与"逻辑连接起来实现"并且"的效果时,可以使用d ...