本文档适用于基于迅雷区块链技术,进行合约应用开发的企业或者个人开发者。
指导用户进行注册、企业和个人资质认证,合约提交、测试和发布。基于智能合约技术进行应用开发。
区块链是一种去中心化的分布式计算系统,主要的特点是数据永久不可篡改性、不可伪造、公开透明信任度高。核心的技术包括拜占庭容错的共识算法(PBFT)、加密技术、P2P技术等。
迅雷链(ThunderChain)是迅雷旗下网心科技创新打造了具备百万tps高并发、秒级确认能力的高性能区块链,并在此基础上,搭建了迅雷链开放平台,助力开发者快速开发、部署智能合约,企业或个人可以轻松将自己的产品和服务上链,更加便捷地开发区块链应用。
区块链可以理解为一个全局共享的交易数据库系统。任何有权限的软件都可以读取区块链网络中的数据。当需要改变区块网络中的数据时,就必须发起一个被所有区块节点接受的请求,这个请求在系统中统称为交易(Transaction)。
交易具有事务性,提交到区块链,要么全部不执行,要么全部执行。一个交易执行完成后永久保存到区块链,不能再做修改和再次执行。
交易由系统中的账户(Account)发起并且签名,通过加密技术,交易只能由私钥持有人发起,其他人不能修改和伪造。这样保证了交易的真实和安全。
在区块链系统中有两类账户,一个是外部账户,一个是合约账户。外部账户拥有自己独有的公私密钥,账户由这个密钥对控制。合约账户有自己的代码,账户由自己的代码控制。
账户由一个地址标识,地址长度是一样的,两类账户无差别。外部账户的地址由其公钥产生,合约地址使用创建合约账户的地址以及创建合约账户的交易数(nonce)产生。迅雷链开放平台的合约由官方地址统一部署,普通账户在迅雷区块链不能发布合约。用户的合约必须经过官方评审,由迅雷统一发布。
在系统内部,对待这两类账户是无差别的。每个账户在系统内部有一个256bits到256bits的key-value存储结构,叫做storage。每个账户有个余额叫做balance,单位是wei,可以通过发送带数值的交易到账户进行修改。
合约就是存储了代码的区块链账户,通过给这个账户发送交易实现合约调用。当前比较流行的合约编程语言是Solidity。当前开放平台支持基于EVM的Solidity语言和基于WASM的C/C++语言开发的合约。
合约内容为两个部分,数据储存和函数,数据存储着合约的状态,函数是合约对外的接口,通过调用函数实现数据查询和状态修改。
通过Solidity编写合约,编译后得到EVM字节码。通过给合约账户发送交易,实现合约调用。
Gas是区块链的付费单位,一个交易创建的时候,会指定支付一定数量的Gas。主要是为了约束交易的运算量,以及为交易执行支付费用。交易执行过程中,Gas会以一个EVM设定的规则消耗。
Gas价格(Gas price)是由交易创建者指定的一个值,交易执行需要支付的费用数量为Gas_Price*Gas。交易结束如果Gas有剩余,剩余部分会返回给创建交易的用户。如果Gas不足,交易执行会失败,为了系统安全防止泛洪攻击,交易失败的手续费不返回。Gas价格的最小单位是wei,10^18 wei = 1 迅雷链token。Gas_Price当前固定取值为10^11,暂时没有开放自由设定。
Solidity是针对智能合约设计的一门高级编程语言,运行环境是EVM(Ethereum Virtual Machine)。语言设计实现中受到了C++/Python/JavaScript的影响。Solidity是强类型语言,支持继承、多态、接口、抽象、库、自定义数据类型等特性。Solidity支持汇编指令编程,代码编译为字节码后运行在EVM上。Solidity是当下最流行的智能合约开发语言,也是迅雷合约平台推荐和支持的语言。
迅雷链(ThunderChain)是迅雷旗下网心科技创新打造了具备百万tps高并发、秒级确认能力的高性能区块链,并在此基础上,搭建了迅雷链开放平台,助力开发者快速开发、部署智能合约,企业或个人可以轻松将自己的产品和服务上链,更加便捷地开发区块链应用。
迅雷链开放平台是网心科技基于“迅雷链”倾力打造的区块链服务开放平台。开放迅雷十余年的分布式技术沉淀和上亿用户基础,共享迅雷链生态数百万活跃人群,以高起点领跑行业,共同构建全球领先的区块链生态。
基于迅雷链,提供稳定、快速、低成本的智能合约区块链服务,支持金融、电商、游戏、社交等各种行业应用场景。助力开发者快速部署智能合约,企业可以轻松将自己的产品和服务上链,更加便捷地开发区块链应用。
个人或者企业开发者要使用智能合约功能前,必须先注册为平台的用户。手机号码是用户唯一标识。注册成功后,可以绑定邮箱。登录
注册流程如下:
绑定邮箱后,方便接收消息通知,方便与官方联系。在忘记密码的情况下,可以通过邮箱重置密码。立即绑定
用户忘记密码后,无法登陆系统。可以通过手机号或者邮箱地址重置密码。
个人开发者要提交使用合约功能,必须先进行个人信息认证。在进行个人认证前,请先注册为平台用户。请准备好身份证,以及身份证正反面照片(必须包含本人头像,照片清晰)。
企业开发者需要进行企业认证,认证信息包括企业名称、营业执照扫描件、法人代表身份证扫描件或者授权书扫描件。企业认证通过后,可以进行智能合约功能使用。
智能合约是和应用关联的,在提交和使用合约之前,必须创建一个应用,否则不能使用这些功能。用户需要将应用信息提交开放平台审核。 应用分为两种类型,移动应用和web应用。移动应用需要提供可下载或验证的软件包。web应用必须提供可访问的网址以及网站注册信息。
使用开放平台创建合约之前,请先确认合约已提交测试环境并经过功能测试。
selfdestruct
代码进行合约销毁。Catalyst使用指南 智能合约solidity开发框架truffle。 提供了一套完善的开发、调试、编译、部署、测试的本地环境。
npm i -g truffle
[root@opennode sandai]# truffle version
Truffle v4.1.5 (core: 4.1.5)
Solidity v0.4.21 (solc-js)
使用truffle 初始化合约工程
mkdir simple-storage
cd simple-storage
truffle init
新建合约文件:可以使用 truffle create contract SimpleStorage
命令行新建,也可以直接新建文件 contract/SimpleStorage.sol
// SimpleStorage.sol
pragma solidity ^0.4.21;
contract SimpleStorage {
uint myVariable;
function set(uint x) public {
myVariable = x;
}
function get() constant public returns (uint) {
return myVariable;
}
}
添加migrate脚本:可以使用truffle create migration 2_deploy_contract
命令行方式新增,也可以直接新建文件 migrations/2_deploy_contract.js
// 2_deploy_contract.js;truffle migrate命令的执行顺序与文件名有关,所以多个部署脚本需要按照顺序命名
var SimpleStorage = artifacts.require("SimpleStorage");
module.exports = function(deployer) {
deployer.deploy(SimpleStorage);
};
执行truffle compile编译合约,编译后的合约在build文件夹下。每个合约有一个对应的json文件,内含部署所需的bytecode,abiCode等
编辑 truffle.js ,设置truffle部署合约及与区块链交互的rpc连接。
[root@localhost opennode]# vi truffle.js
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*"
}
}
};
控制台开启truffle默认的区块链环境。
truffle develop
Truffle Develop started at http://127.0.0.1:9545/
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.
truffle(develop)>
这为truffle运行合约提供了本地的区块链环境,默认生成10个账户,每个账户初始余额为100ether。 也可以使用Ganache提供的图形化界面应用,需要修改配置连接的端口。
在一个新的控制台执行truffle migrate移植部署合约(或者在truffle develop控制台执行 migrate)。
使用truffle develop测试合约代码。
SimpleStorage.deployed().then(function(instance){return instance.get.call();}).then(function(value){return value.toNumber()})
// 0
SimpleStorage.deployed().then(function(instance){return instance.set(100);});
// 输出transaction信息
SimpleStorage.deployed().then(function(instance){return instance.get.call();}).then(function(value){return value.toNumber()});
// 100
使用truffle test 测试合约 使用truffle create test SimpleStorage新建或直接新建文件test/SimpleStorage.test.js。
const SimpleStorage = artifacts.require('SimpleStorage');
contract('SimpleStorage', function(accounts) {
it("should assert true", function(done) {
var simpleStorage = SimpleStorage.deployed();
var instance;
simpleStorage.then(res => {
instance = res;
return instance.get()
}).then(value => {
assert.equal('0', value.toNumber(), 'not equal 0')
}).then(() => {
instance.set(100)
}).then(() => {
return instance.get()
}).then(value => {
assert.equal('100', value.toNumber(), 'not equal 100')
})
done();
});
});
在新开的控制台里,输入truffle test ./test/SimpleStorage.test.js
。
使用remix测试合约 将使用truffle 开发的合约,放在remix里,可快速模拟合约的部署和调用。 remix提供了合约的编译运行环境,并可以在控制台看到合约每条交易的详细信息,如输入输出参数,签名后的方法data,交易hash等信息。支持调试。
使用compile detail,可以看到合约编译详情。包括bytecode,abi和使用web3.js快速部署的方法。
使用run来create 合约,控制台可查看创建合约的交易。
上面的步骤使用基本的truffle init创建了一个可编译部署调试的合约环境。 下面使用truffle unbox创建一个新的工程,unbox为我们提供了truffle工程模板,内置了一些合约应用交互的环境依赖。 可以在truffle boxes里查看官方提供的各种模板boxes。 下面使用的是react模板.
新建工程 truf-react
mkdir truf-react
cd truf-react
truffle unbox react
unbox过程会下载解压模板,执行npm install等操作。
配置项目的truffle.js
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
networks: {
development: {
host: '127.0.0.1',
port: '9545',
network_id: '*' // Match any network id
}
}
};
启动一个truffle develop
修改src/App.js
import React, { Component } from 'react'
import SimpleStorageContract from '../build/contracts/SimpleStorage.json'
import getWeb3 from './utils/getWeb3'
import './css/oswald.css'
import './css/open-sans.css'
import './css/pure-min.css'
import './App.css'
const contract = require('truffle-contract')
const simpleStorage = contract(SimpleStorageContract)
class App extends Component {
constructor(props) {
super(props)
this.state = {
storageValue: 0,
web3: null,
inputValue: 0,
address: null
}
this.changeValueHandle = this.changeValueHandle.bind(this)
this.setHandle = this.setHandle.bind(this)
}
componentWillMount() {
// Get network provider and web3 instance.
// See utils/getWeb3 for more info.
getWeb3
.then(results => {
this.setState({
web3: results.web3
})
// Instantiate contract once web3 provided.
this.instantiateContract()
})
.catch(() => {
console.log('Error finding web3.')
})
}
instantiateContract() {
/*
* SMART CONTRACT EXAMPLE
*
* Normally these functions would be called in the context of a
* state management library, but for convenience I've placed them here.
*/
this.simpleStorageSet(5)
}
changeValueHandle(event) {
this.setState({
inputValue: Number(event.target.value)
})
}
setHandle() {
this.simpleStorageSet(this.state.inputValue)
}
simpleStorageSet(x) {
simpleStorage.setProvider(this.state.web3.currentProvider)
// Declaring this for later so we can chain functions on SimpleStorage.
var simpleStorageInstance
// Get accounts.
this.state.web3.eth.getAccounts((error, accounts) => {
simpleStorage.deployed().then((instance) => {
simpleStorageInstance = instance
this.setState({ address: instance.address })
// Stores a given value, 5 by default.
return simpleStorageInstance.set(x, {from: accounts[0]})
}).then((result) => {
// Get the value from the contract to prove it worked.
return simpleStorageInstance.get.call(accounts[0])
}).then((result) => {
// Update state with the result.
return this.setState({ storageValue: result.c[0] })
})
})
}
render() {
return (
<div className="App">
<nav className="navbar pure-menu pure-menu-horizontal">
<a href="#" className="pure-menu-heading pure-menu-link">Truffle Box</a>
</nav>
<main className="container">
<div className="pure-g">
<div className="pure-u-1-1">
<h1>Good to Go!</h1>
<p>Your Truffle Box is installed and ready.</p>
<h2>Smart Contract Example</h2>
<p>If your contracts compiled and migrated successfully, below will show a stored value of 5 (by default).</p>
<p>Try changing the value stored on <strong>line 59</strong> of App.js.</p>
<p>The stored value is: {this.state.storageValue}</p>
<p>deployed contract address: {this.state.address}</p>
</div>
<div>
<input type="number" onChange={this.changeValueHandle}/>
<button onClick={this.setHandle}>set</button>
</div>
</div>
</main>
</div>
);
}
}
export default App
新增了合约set方法的调用。并展示了合约的address。
新打开一个控制台,执行 npm run start
通过set和输入框设置合约storedData的值。
在trufle develop里输入
//将xxx替换为address
SimpleStorage.at('xxxx').then(res => {return res.get()})
// 得到BigNUmber类型的返回值,c数组里的值即为设置的storedData的值。
参考 http://truffleframework.com/tutorials/pet-shop
solidity API
truffle文档
ganache 提供本地区块链环境的图形化界面
zeppelin-solidty 致力于安全的标准化的合约框架
web3.js 以太坊封装的与区块链交互的js
Smart Contract Security Best Practices(合约安全开发指南)
合约的调用和查询,传入的参数是根据合约ABICode编码后函数和函数参数的data。详细可参考solidity - Application Binary Interface Specification
下面介绍几种方式取得合约ABICode方法调用时对应的编码data。
在使用remix执行合约方法时,每次交易都有对应的交易详情,可以在控制台看到交易信息里的函数调用的input,以及对应的decodeInput和decodeOutput。
input就是调用函数时向区块链环境发送的JSON里的data。对应开放平台,在使用合约调用时,传入的data可以直接使用remix的data。
ethers.js是一个以太坊的js依赖包。里面提供了根据ABICode编码函数名的方法和编码参数的静态方法。
例:
//HelloWorld.sol
pragma solidity^0.4.23;
contract HelloWorld {
address public owner;
string public info;
constructor(address _owner) public {
owner = _owner;
}
function saySomething(string _str) public returns(string) {
info = _str;
return info;
}
}
//编码function saySomething函数的 abi
var ethers = require('ethers')
var abi = [
{
"constant": false,
"inputs": [
{
"name": "_str",
"type": "string"
}
],
"name": "saySomething",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"constant": true,
"inputs": [],
"name": "info",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
];
var interface = new ethers.Interface(abi)
var abiInstance = interface.functions[abi[0].name] // abi[0]即saySomething function的abi
return abiInstance.sighash // 0xfe6b3783
获取函数参数编码data的方法:
使用ethers.utils.ABICoder的encode方法,如
// 编码 function saySomething 的输入参数 'Hello World'的data
var abiCoder = new ethers.utils.AbiCoder()
return abiCoder.encode(['string'], ['Hello World'])
//0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
实际调用函数的input即为:函数saySomething encode
的前八位 + 函数输入参数的encode。结果为
0xfe6b37830000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
可对比上面使用remix调用方法时的input值,两者结果一致。
合约执行结束后,info值被设置为 "Hello World"。下面请求constant方法(同8.3 Demo合约查询),根据结果解析info值。
curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xd5b0df861803a07f330868104eec92ebdcce4c79","data":"0x370158ea"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"}
var ethers = require('ethers')
var outputTypes = ['string']
var response = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"
var abiCoder = new ethers.utils.AbiCoder()
abiCoder.decode(outputTypes, response)
// [ 'Hello World' ]
decode结果根据传入的outputTypes数组长度,解析对应的参数。
开发者开发合约完成后,需要先提交到迅雷链测试环境部署和测试。经测试验证无误后,再向开放平台提交合约,部署正式环境。经官方审核代码后才可部署正式环境。
获取邮箱验证码
接口,验证码有效期30分钟,每个未注册邮箱24小时内最多请求3次验证码。使用邮箱注册
接口,使用上一步的验证码和邮箱注册。测试账号充值
接口。合约发布
接口,部署合约到迅雷链测试环境。例:
contract HelloWorld {
address owner;
constructor(address ownerArg) public {
//owner = msg.sender; 使用ownerArg代替msg.sender
owner = ownerArg;
}
}
在接入正式环境之前,需要将合约在测试环境部署并经过完善的功能测试,才能提交正式环境的审核。
提交开放平台正式审核时,平台方会根据提交到正式环境源码和对应的bytecode做校验审核。
步骤如下
注意:
正式环境合约的调用和查询与测试环境的API和流程一致,请求host不同。详情见API列表。
合约调用指需要改变合约状态的函数调用,执行函数的同时也可以转账到合约账户。用户界面输入用户请求后,触发合约调用。
合约调用当前分为两种形式:通过迅雷链助手App扫描二维码发送合约调用的交易;通过业务方App唤起迅雷链助手发起合约调用的交易。
典型的第三方合约应用的调用流程如下(分为面向C端的调用和面向B端的运营调用):
步骤如下:
第三方应用可以同步数据到其后台服务。(第三方功能)
区块链后台将合约调用请求处理完后,如果用户有填写回调信息,回调中心通知第三方应用后台(参考 回调协议)。第三方应用界面会同第三方应用后台同步信息,展示交易后的结果。
例:从玩客云调用迅雷链助手
vchouyi://payment/?tx-data=ZGVzYz3nlLXlvbFYWFhYJnRvPTB4MTIzNDU2Nzg5MDEyMzQ1Njc4OTAmdmFsdWU9MTIzLjQwJmdhc2xpbWl0PTUwMDAwJmRhdGE9MHgwMTAyMDMwNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEmc2lnbj0wNEI3QTU1QzQ3NDQwRDk4NUE0NDgzNkZENTVFQkVCNw==&resource=d2t5&x-source=wky&callback=wky://x-callback-url/&cb-data=base64编码后的回调透传参数
具体解析
解码后包含如下信息
APP回调返回
(http://www.xx.com|scheme://host)?hash=交易回执&msg=错误描述(base64)&code=错误码&cb-data=透传信息&result=(success|fail|cancel)
步骤如下:
请求url返回的结构
{
"iRet":0,
"sMsg": "ok",
"data": {
"tx_data": ""
}
}
查询合约constant状态和方法,不消耗gas,使用eth_call API方法直接调用。
样例: Example
在合约部署成功的情况下,执行以下操作:
[root@t05f058s2 ~]# curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xfe2587bdc1781f23d105002c328d3d2ea6cfcbdd","data":"0xb0f0c96a0000000000000000000000000000000000000000000000000000000000000005"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"error":{"message":"invalid request","code":-32600},"jsonrpc":"2.0","id":1}
[root@t05f058s2 ~]# curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xe0e39a57a044451a00e4c73a2ea6bf83bd229a68","data":"0xb0f0c96a0000000000000000000000000000000000000000000000000000000000000005"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000007eff122b94897ea5b0e2a9abf47b86337fafebdc0000000000000000000000000000000000000000000000000000000000000005"}
to: 部署合约成功之后,获得的合约地址
data: 计算方法
abi=[{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"value","type":"uint256"}],"name":"hello","outputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
ctx=eth.contract(abi).at('0xc197e61edcbccc4bf7a0f76250ca7246de03e773')
ctx.hello.getData.call(null, 5, {from:from})
"0xb0f0c96a0000000000000000000000000000000000000000000000000000000000000005"
功能
获取邮箱验证码用于测试用户注册。
请求
方法:POST
URL: /api/linktest/email_code
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
功能
测试注册接口,使用email地址。用户第一次注册,产生service_id/secret通过邮件形式发送给开发者。如果邮箱地址已经注册,返回错误码。
请求
方法:POST
URL: /api/linktest/regist
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email,主要用于接收测试消息 | |
emailcode | string | 是 | 注册前使用的邮件验证码 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
功能
申请将测试燃料充值到指定的账户,开发者给自有的账户充值后用于测试活动。
每申请一次转入10个测试燃料。每个email每天最多调用10次。
也可以通过Catalyst工具直接领取测试燃料。
请求
方法:POST
URL: /api/linktest/recharge
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email,主要用于接收测试消息 | |
address | string | 是 | 需要充值的账号地址 |
sign | string | 是 | 签名md5(email=xxx&address=xxx&secret=xxx), xxx填写请求的实际值 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
功能
用户发布合约到测试环境,用户提供编译后的字节码。
请求
方法:POST
URL: /api/linktest/contract/deploy
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email,主要用于接收测试消息 | |
bytecode | string | 是 | 编译后的合约字节码,十六进制ABI格式 |
params | string | 否 | 构造函数初始化参数,十六进制ABI格式 |
sign | string | 是 | 签名md5(email=xxx&bytecode=xxx¶ms=xxx&secret=xxx), xxx填写请求的实际值。即使params为空也需要计算到sign里 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
data
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
id | int | 是 | 合约部署产生的id,通过这个id可查询合约部署后的地址 |
功能
通过合约部署产生的id查询合约账户地址。
请求
方法:POST
URL: /api/linktest/contract/address
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email,主要用于接收测试消息 | |
id | int | 是 | 合约部署返回的id |
sign | string | 是 | 签名md5(email=xxx&id=xxx&secret=xxx), xxx填写请求的实际值 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
data
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
address | string | 是 | 账户地址 |
功能
查询最近部署的合约id和合约地址。
请求
方法:POST
URL: /api/linktest/contract/last
BODY: JSON
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试使用的email,主要用于接收测试消息 | |
sign | string | 是 | 签名md5(email=xxx&secret=xxx), xxx填写请求的实际值 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
data
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
id | int | 是 | 合约ID |
address | string | 是 | 账户地址 |
功能
开发者提交交易信息,获取到一个交易URL用于扫码支持。支持合约支付和第三方支付。
此接口是为了方便开发者测试,已封装了请求prepay_id的流程,仅适用于测试环境。正式环境不提供此接口,需要开发者后台实现prepayid接口和url请求。
请求
方法:POST
URL: /api/linktest/tx_generate
BODY: JSON
请求参数
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
string | 是 | 测试注册的email | |
to | string | 是 | 合约地址或者账户地址 |
value | string | 是 | 转入的token数量,十进制整数,单位wei |
callback | string | 是 | 回调URL |
title | string | 是 | 交易信息标题,例如:“合约调用-存证信息上链” |
desc | string | 是 | 交易详细信息,例如:“兑换xxx服务” |
gas_limit | string | 否 | 执行合约最多消耗GAS值,十进制整数,合约交易才填 |
data | string | 否 | 执行的合约代码,十六进制字符串,以0x开头。包含函数地址和调用参数。只发起转账,这个内容为空。合约交易才填 |
tx_type | string | 是 | 交易类型,合约交易:contract, 第三方交易:tx_third |
sign | string | 是 | 请求签名,用于校验请求真实性 md5(email=xxx&to=xxx&value=xxx&secret=xxx) |
响应
BODY: JSON
响应参数
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
code | int | 是 | 错误码,0:成功 非0:失败 |
msg | string | 是 | 错误提示信息 |
data | object | 否 | 请求返回数据 |
data
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
url | string | 是 | 生成的URL,用于扫码获取交易信息 |
expire | int | 是 | URL过期时间,单位毫秒 |
功能
获取订单详细信息,请求URL由接口(/api/linktest/tx_generate)生成。
开发者通过迅雷链助手APP扫码获取订单URL,迅雷链助手APP请求此URL获取交易信息,签发交易
请求
方法:GET
URL: /api/linktest/tx_info/:tx_id
BODY: null
参数说明:
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
tx_id | string | 是 | 携带在path中的参数,动态交易ID,十六进制字符串 |
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
content | stream | 是 | 迅雷链助手APP支付协议格式的交易信息 |
唤起协议
合约执行必须通过迅雷链助手,由第三方应用唤醒迅雷链助手App或者通过迅雷链助手App扫码。 迅雷链助手唤起协议为vchouyi://payment?
请求参数说明
参数 | 类型 | 必须 | 说明 |
---|---|---|---|
scheme | string | 是 | 迅雷链助手scheme vchouyi |
host | string | 是 | 迅雷链助手host值为:payment |
tx-data | byte[] | 是 | Base64编码 主要包含支付的订单信息,key=value形式,以&连接 |
resource | byte[] | 是 | Base64编码 来源app(来源商户名称),限制10字符以内 |
cb-data | byte[] | 否 | Base64编码(可选)支付调起者需要迅雷链助手回传的额外信息 |
x-source | string | 否 | 源app scheme eg. wky-app(可选 iOS调用回调,安卓不处理),保留字段 |
callback | string | 否 | url编码,支付完成后,回调迅雷链助手的地址或者schema http://www.xx.com 或 scheme://host/?hash=交易回执&msg=错误描述(base64)&code=错误码&cb-data=透传信息&result=(success|fail|cancel) |
iOS-User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E302 OneWallet/2.0.3 (iPhone; iOS 11.3.1; Scale/3.00; origin/2; nc/IN)
tx-data参数说明
参数 | 类型 | 必须 | 说明 |
---|---|---|---|
desc | string | 是 | 合约执行描述,必须带上“合约执行-”前缀 |
callback | string | 否 | 做url编码,第三方应用后台用来接收区块链交易完成后的回调地址 |
to | string | 是 | 执行的合约地址 |
value | string | 是 | token数量(单位 wei),1 token = 10 ** 18 wei ,传整数,不带单位。如转1token的时候填写 1 000 000 000 000 000 000 |
prepay_id | string | 是 | 预支付订单号,通过接口getPrepayId 获取 |
service_id | string | 是 | 业务id,通过迅雷链开放平台申请获取service_id和签名秘钥 |
data | string | 否 | 如果是合约执行,传入以0x开头的执行合约函数和参数的编码。 |
gas_limit | string | 否 | 最大的支付gas:合约交易时为估算的执行手续费;若交易费超出实际执行扣取,会退还回付款方; |
tx_type | string | 否 | 合约交易时,固定取值contract; |
sign | string | 是 | 交易签名 sign=md5(sha512(callback=xxx&prepay_id=xxx&service_id=xxx&to=xxx&value=xxx&key=私钥)) 此处的callback url不用编码 |
APP回调返回
(http://www.xx.com|scheme://host)?hash=交易回执&msg=错误描述(base64)&code=错误码&cb-data=透传信息&result=(success|fail|cancel)
该方法用来做合约方法查询。 该方法是用来执行指定的message call,不会创建交易,因此该方法的调用是试用不会改变区块链状态数据库的,合约中的constant方法应该调用这个方法。
请求
方法:POST
URL: /call
BODY: JSON
参数说明:
字段 | 类型 | 约束 | 备注 |
---|---|---|---|
jsonrpc | String | 必须 | 固定值 "2.0" |
method | String | 必须 | 固定值 "eth_call" |
params | Array | 必须 | 详细信息见下面表格 |
id | Int | 必须 | 固定值 1 |
params 详细
index | 类型 | 约束 | 备注 |
---|---|---|---|
0 | Object | 必须 | 结构如下object详细 |
1 | String | 必须 | 固定值 "latest" |
object 详细
字段 | 类型 | 约束 | 大小 | 备注 |
---|---|---|---|---|
from | common.Address | 必须 | 20 bytes | 交易的发起者 |
to | common.Address | 必填 | 20 bytes | 交易指向的地址,比如合约调用方法中就是合约地址 |
data | hexutil.Bytes | 可选 | 执行合约constant方法和参数的编码 详见 Ethereum Contract ABI |
示例
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"from": "",
"to": "",
"data": ""
},
"latest"
],
"id": 1
}
响应
字段 | 类型 | 约束 | 大小 | 备注 |
---|---|---|---|---|
DATA | 交易调用对象 | 合约执行结果 |
功能
获取合约调用预估消耗的gas数量。用户在调用合约时需要传入gas_limit值,由于gas的消耗与区块链当前运行环境的难度值等相关,需实时计算。
如果调用合约执行时out-of-gas(即gas消耗完但合约还未执行完毕),则合约执行失败,并且已消耗的gas不会返还。
如果调用合约执行时的gas小于或等于提供的gas,则合约执行完毕,将退还未消耗的gas。
建议开发者在调用合约时,在此计算出的预计gas消耗值基础上加上一些,以保证合约执行成功。
请求
方法:POST
URL: /estimateGas
BODY: JSON
参数说明:
字段 | 类型 | 约束 | 备注 |
---|---|---|---|
jsonrpc | String | 必须 | 固定值 "2.0" |
method | String | 必须 | 固定值 "eth_estimateGas" |
params | Array | 必须 | 详细信息见下面表格 |
id | Int | 必须 | 固定值 1 |
params 详细
index | 类型 | 约束 | 备注 |
---|---|---|---|
0 | Object | 必须 | 结构如下object详细 |
object 详细
字段 | 类型 | 约束 | 大小 | 备注 |
---|---|---|---|---|
from | common.Address | 可选 | 20 bytes | 交易的发起者 |
to | common.Address | 必填 | 20 bytes | 交易指向的地址,比如合约调用方法中就是合约地址 |
value | hexutil.Big | 可选 | 该交易要发送的值 | |
data | hexutil.Bytes | 可选 | Hash of the method signature and encoded parameters. 详见 Ethereum Contract ABI |
示例
{
"jsonrpc": "2.0",
"method": "eth_estimateGas",
"params":[
{
"from": "",
"to": "",
"data": "",
"value": ""
}
],
"id": 1
}
响应
参数名 | 参数类型 | 必须 | 说明 |
---|---|---|---|
content | stream | 是 | 迅雷链助手APP支付协议格式的交易信息 |
请求方式: post
参数 | 类型 | 说明 |
---|---|---|
service_id | int | 业务号,通过迅雷链申请 |
sign | string | 签名,签名算法:md5(sha512("service_id=业务号&key=私钥")) |
timeout | int | 生成的prepay_id的有效期,单位为秒 |
请求格式与示例:
//为了保持和以太坊格式一致,请求post body数据要按照以下格式:
{
"jsonrpc": "2.0",
"method": "getPrepayId",
"params": {
"service_id": 0,
"sign": "f93d2813227b68f77bf0db84c62011ca",
"timeout": 1800
}
}
响应参数:
参数 | 类型 | 说明 |
---|---|---|
iRet | int | 0 成功 |
sMsg | string | 返回描述 |
data | json object | 成功返回prepay_id: 'xxxx',失败返回错误信息 |
返回示例:
{
"iRet":0,
"sMsg": "ok",
"data": {"prepay_id":"201711291656030000000101431771972107"}
}
请求url
测试环境:https://sandbox-blockchain.xunlei.com/getOrderStatusByPrepayId
正式环境:https://rpc-blockchain.xunlei.com/getOrderStatusByPrepayId
参数 | 类型 | 说明 |
---|---|---|
service_id | int | 业务号,通过迅雷链申请 |
prepay_id | string | 订单提交时获取的 |
请求格式与示例:
{"jsonrpc":"2.0","method":"getOrderStatusByPrepayId","params":{"service_id":1,"prepay_id":"20171019xxxxxxxxxxxx"}}
响应参数:
参数 | 类型 | 说明 |
---|---|---|
iRet | int | 0 成功 |
sMsg | int | 返回描述 |
data | array | 返回数据,json编码的字符串 |
data格式:
参数 | 类型 | 说明 |
---|---|---|
from | string | 付款地址 |
to | string | 收款地址 |
value | string | token数量,string,单位:wei, 例如:"1000000000000000000" |
status | string | 订单状态,0初始,1成功,2失败 |
ctime | string | 交易时间,例:2017-10-19 15:37:00 |
hash | string | 交易hash |
payload | string | 交易payload |
返回示例:
{
"iRet":0,
"sMsg":"success",
"data":{
"from":"0x7b6837189a3464d3c696069b2b42a9ae8e17dda1",
"to":"0x00a2810b56e763406cad8be8ee90b0b89b370829",
"value":"1000",
"ctime":"2018-12-28 11:56:00",
"status":0,
"hash":"0xe254b5a67458e8d2b20472028738baba7bf5f10c5fd19f471b31c6725e58b10e",
"pay_load":""
}
}
交易成功后,区块链通知模块会把prepay_id回调接入方,接入方需要接收处理,并返回应答。
对后台通知交互时,如果区块链通知模块收到接入方的应答不是成功或超时,区块链通知模块认为通知失败,区块链通知模块会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但区块链通知模块不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
注意:同样的通知可能会多次发送给接入方系统。接入方系统必须能够正确处理重复的通知。
推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
特别提醒:接入方系统对于交易结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”。
区块链通知模块回调协议(post):
参数 | 类型 | 说明 |
---|---|---|
prepay_id | string | 预支付ID |
from | string | 付款地址 |
to | string | 收款地址 |
value | string | token数量,string,单位:wei, 例如:"1000000000000000000" |
status | string | 订单状态,0初始,1成功,2失败 |
timestamp | string | unix时间戳 |
sign | string | md5(sha512(from=xxxxxx&prepay_id=xxxxxxxxxxxxx&status=1×tamp=1512893272&to=xxxxx&value=xxxx&key=私钥)) |
示例:
from=xxxxxx&prepay_id=xxxxxxxxxxxxx&status=1×tamp=1512893272&to=xxxxx&value=100000000000000&sign=4124bc0a9335c2xxxxxxxxxxxxxx
其中的sign=md5(sha512(from=xxxxxx&prepay_id=xxxxxxxxxxxxx&status=1×tamp=1512893272&to=xxxxx&value=xxxx&key=私钥))
接入方收到回调后,需要给区块链通知模块回应(response):
return_code=0&return_msg=ok
pragma solidity^0.4.23;
contract HelloWorld {
address public owner;
string public info;
constructor(address _owner) public {
owner = _owner;
}
function saySomething(string _str) public returns(string) {
info = _str;
return info;
}
}
使用邮箱注册测试环境账号,获取service_id和key。开发者可以自己实现接口请求或使用postman等工具来注册。
下面提供apiary的api接口用于注册。调用接口时需根据实际情况计算sign和修改请求参数。
下载测试版迅雷链助手,新建个人测试用账户。使用第一步里的接口向对应的账户充值。
编译合约,获取部署合约所需的bytecode。
这里如果使用truffle开发的话,可以使用truffle compile
命令编译合约 /build 文件夹下获取对应合约的json文件,提取对应的bytecode。
如果使用remix开发合约的话,点击 compile => Details 获取对应的bytecode。
// HelloWorld.sol bytecode
0x608060405234801561001057600080fd5b506040516020806104f783398101806040528101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610474806100836000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063370158ea1461005c5780638da5cb5b146100ec578063fe6b378314610143575b600080fd5b34801561006857600080fd5b50610071610225565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100b1578082015181840152602081019050610096565b50505050905090810190601f1680156100de5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100f857600080fd5b506101016102c3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561014f57600080fd5b506101aa600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506102e8565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101ea5780820151818401526020810190506101cf565b50505050905090810190601f1680156102175780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102bb5780601f10610290576101008083540402835291602001916102bb565b820191906000526020600020905b81548152906001019060200180831161029e57829003601f168201915b505050505081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606081600190805190602001906103009291906103a3565b5060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103975780601f1061036c57610100808354040283529160200191610397565b820191906000526020600020905b81548152906001019060200180831161037a57829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106103e457805160ff1916838001178555610412565b82800160010185558215610412579182015b828111156104115782518255916020019190600101906103f6565b5b50905061041f9190610423565b5090565b61044591905b80821115610441576000816000905550600101610429565b5090565b905600a165627a7a72305820e93b6ccfaace4a512cc7b4a45ba826b940ce758758fe21abe52cb4c1fecf211f0029
如果合约的构造函数带有初始化参数,需要计算初始化参数params的data。
如果使用remix开发合约的话,点击 run,选中要部署的合约,输入初始化参数,点击 deploy。在控制台中可以查看此交易的详细信息,其中的input即为合约编译的bytecode与初始化参数组成的data。由于测试环境的部署接口,将合约编译的bytecode与初始化参数的params分离开来,所以这里需要将params对应的data单独提取。
如果使用的是ethers.js,利用ethers.utils.ABICoder
的encode方法,编译对应的初始化参数为部署合约的params。
var ethers = require('ethers')
var abiCoder = new ethers.utils.AbiCoder()
return abiCoder.encode(['address'], ['0xca35b7d915458ef540ade6068dfe2f44e8fa733c'])
// 0x000000000000000000000000ca35b7d915458ef540ade6068dfe2f44e8fa733c
调用测试环境测试环境部署合约
接口,参数为上述的bytecode、params以及部署合约的email和计算的签名sign。请求结果会返回一个部署合约的id。
然后调用根据id查询合约地址
接口,查询已部署合约的地址。
调用 查询合约constant方法
接口,查询HelloWorld的info值。
根据合约查询编码的方法,计算得info的data为 0x370158ea
。
curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xd5b0df861803a07f330868104eec92ebdcce4c79","data":"0x370158ea"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"}
// AbiCoder.decode解码得值为空
初始化函数时,info值为空。
编码 saySomething
函数,获取调用函数的data。参考使用ethers.js编码。
0xfe6b37830000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000
请求 查询预估gas消耗
接口,查询saySomething 函数执行的预估gas值。建议传入执行调用函数的gas值在查询的gas值基础上加上一些,以防出现out-of-gas的情况。
curl -k -XPOST --data '{"jsonrpc":"2.0", "method":"eth_estimateGas", "params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xd5b0df861803a07f330868104eec92ebdcce4c79", "data":"0xfe6b37830000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000","value":""}], "id":1}' -H 'content-type:application/json' https://sandbox-blockchain.xunlei.com/estimateGas
// 返回值
{"jsonrpc":"2.0","id":1,"result":"0xaebc"}
将上述结果转10进制得:
0xaebc.toString('10')
// "44732"
在传入到下一步的执行接口时,将在此值的基础上加上10000,最终传入的gas数量为54732。
请求接口 生成扫码支付的URL信息
执行合约的 saySomething
函数。
请求参数中的to地址为合约地址0xd5b0df861803a07f330868104eec92ebdcce4c79
,data为前面生成的data,gas_limit为上一步的54732。
计算sign md5(email=xxx&to=xxx&value=xxx&secret=xxx)。
返回 data 的里 url 即为迅雷链助手app扫描二维码需要的地址。链接具有时效性,默认30分钟。
{
"code": 0,
"data": {
"url": "http://fe-blockchain.xunlei.com/#/?action=https%3A%2F%2Fsandbox-blockchain.xunlei.com%2Fapi%2Flinktest%2Ftx_info%2Ff4ebcdf4d756f0d8041c82d8e32e912a",
"expire": 1800000
},
"msg": ""
}
根据上一步的url,使用二维码生成工具,生成一个二维码。然后使用测试版迅雷链助手app扫描。
迅雷链助手将调用合约执行页面,用户选择执行合约使用的账户,输入对应的密码。等待交易确认后,交易记录里可以看到合约执行结果。
再次调用 查询合约constant方法
接口,查询HelloWorld的info值。
curl -k -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from":"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc","to":"0xd5b0df861803a07f330868104eec92ebdcce4c79","data":"0x370158ea"}, "latest"],"id":1}' https://sandbox-blockchain.xunlei.com/call
{"jsonrpc":"2.0","id":1,"result":"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"}
// AbiCoder.decode解码得值为 Hello World,调用成功
生成扫码支付的URL信息
接口,所以开发者需要根据 使用迅雷链助手扫描二维码调用合约中所描述的步骤自己提供二维码所需的url及其对应的后台web服务。扫码下载安装
扫码下载安装
用户下载安装APP后,即可通过APP生成账户。
迅雷链测试环境通过API接口邮件请求获取,请求后会通过邮件通知开发者。
迅雷链正式环境通过迅雷链开放平台申请服务,审核通过后平台下发service_id和key。