1、资产导出时序图
2、术语
接入方:用户资产的外部所有者
平台方:数源卡包
所属链:资产所在的区块链
3、生成签名
使用对接方的corp_secret对Url查询参数进行HMACSHA256
签名
step1 生成公共请求参数(UTC时间戳、nonce随机6位非0开头正整数、corp_id)
step2 将请求数据格式化为Url查询参数的形式
step3 对Url查询参数按照字母升序排列
step4 进行一次UrlEncode后,使用corp_secret对UrlEncode的字符串签名,生成hex字符串
step5 将&sign=签名字符串
追加在UrlEncode后的字符串尾部,即可获得完整的Url查询参数
代码示例
GET https://out.xxxxx.com/assets/exporting/precommit
以请求导出预提交接口
为例(Golang Function)
func SignByUrl(corpSecret string, query *url.Values) (string, string, error) {
queryStr := query.Encode()
hash := hmac.New(sha256.New, []byte(corpSecret))
_, err := hash.Write([]byte(queryStr))
if err != nil {
return "", "", err
}
signData := hash.Sum(nil)
signature := hex.EncodeToString(signData)
queryStr = fmt.Sprintf("%s&sign=%s", queryStr, signature)
return queryStr, signature, nil
}
func DoRequest() {
domain := "https://out.xxxxx.com/assets/exporting/precommit"
corpId := "wn9ybdkn78z33x9fsbu4cu63ft6gnf7m"
corpSecret := "9eysdhsal1212knmo358sdd"
openId := "1554299758581911552"
requestId := "4e523f69-c1c0-484e-8140-d6cd2641fac3"
contractAddress := "0x3A418ed9d8C5Bc3A6382A673526efF05CC314"
tokenId := "21"
query := &url.Values{}
query.Add("contract_address", contractAddress)
query.Add("token_id", tokenId)
query.Add("open_id", openId)
query.Add("request_id", requestId)
// 增加默认字段
timestamp := uint64(time.Now().UTC().Unix())
nonce := rand.Intn(800000) + 100000
query.Add("corp_id", corpId)
query.Add("nonce", strconv.Itoa(nonce))
query.Add("timestamp", strconv.FormatUint(timestamp, 10))
queryStr, _, err := SignByUrl(corpSecret, query)
if err != nil {
return
}
reqUrl := fmt.Sprintf("%s?%s", domain, queryStr)
req, _ := http.NewRequest("GET", reqUrl, nil)
req.Header.Add("Content-Type", "application/json")
client := &http.Client{}
defer client.CloseIdleConnections()
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
var buf bytes.Buffer
_, err = buf.ReadFrom(resp.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(buf.String())
}
4、API列表
(1) 导出预提交
(2) 导出结果回调
(1) 导出预提交
调用接入方的导出预提交接口
确认唯一性的方式:
- contract_address + token_id
- open_id
基本信息
请求方式:GET
请求地址:https://out.xxxxx.com/assets/exporting/precommit
Query参数
名称 | 类型 | 是否必填 | 示例值 | 描述 |
---|---|---|---|---|
contract_address | String | 是 | 0x3A418ed9d8C5Bc3A6382A673526efF05CC314 | 资产所属合约地址 |
token_id | String | 是 | 21 | 资产的tokenID |
open_id | String | 是 | 1554299758581911552 | 资产在接入方的唯一标识 |
request_id | String | 是 | 4e523f69-c1c0-484e-8140-d6cd2641fac3 | 导出请求ID |
corp_id | String | 是 | wn9ybdkn78z33x9fsbu4cu63ft6gnf7m | 平台方分配给接入方的ID |
nonce | String | 是 | 812447 | 签名随机数 |
timestamp | String | 是 | 1656191400 | 平台方请求接入方的时间 |
sign | String | 是 | qywed612ebasad9123nac101ma | 签名字符串 |
返回参数
名称 | 是否必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|
code | 是 | String | 200 | 状态码 |
msg | 是 | String | success | 状态码对应的提示内容 |
data | 否 | Object | 返回内容 |
(2) 导出结果回调
平台方通知接入方转账结果的回调接口,如果接入方同步返回的code不为200,则平台方会尝试通知接入方3次,时间间隔约为(5m,15m,60m)。
基本信息
请求方式:GET
请求地址:https://out.xxxxx.com/assets/exporting/callback
Query参数
名称 | 类型 | 是否必填 | 示例值 | 描述 |
---|---|---|---|---|
request_id | String | 是 | 4e523f69-c1c0-484e-8140-d6cd2641fac3 | 预导出时给予接入方的请求ID |
status | String | 是 | success | 处理状态,success|fail |
tx_hash | String | 是 | 0xa691f0ba50d924672fe5831a17e6c9263cb9as23u | 交易唯一号,平台方保证唯一性 |
corp_id | String | 是 | wn9ybdkn78z33x9fsbu4cu63ft6gnf7m | 平台方分配给接入方的ID |
nonce | String | 是 | 512370 | 签名随机数 |
timestamp | String | 是 | 1659198482 | 平台方请求接入方的时间 |
sign | String | 是 | qywed612ebasad9123nac101ma | 签名字符串 |
返回参数
名称 | 是否必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|
code | 是 | String | 200 | 状态码 |
msg | 否 | String | success | 状态码对应的提示内容 |
data | 否 | Object | 返回内容 |
5、参考状态码列表
当code值不等于200时,返回数据的data为null,并且msg有错误提示信息
code值 | 类型 | 错误内容 |
---|---|---|
200 | String | |
400 | String | 请求参数错误 |
500 | String | 系统错误 |
12015 | String | 签名无效 |