Mixin Network 使用
首先在手机上安装并注册好个人的 Mixin 账户,然后访问 https://developers.mixin.one/dashboard 使用 Mixin 的摄像头扫码登录,完成 App 的注册。
注册成功 App 之后,点击相应 App 的 “Click to generate a new session”,会出现三组数据,第一行的 6 位数字是 App 自己的提现 PIN 码,第二行的 UUID 是 session ID,最后一部分 RSA PRIVATE KEY 是跟 API 进行交互时用来签名 JWT 的私钥。
API 认证方式为标准的 JWT RSA 签名,JWT claims 必须包含的信息为
"uid": 注册的 App 的 ID,
"sid": 上一部分获取的 session ID,
"iat": 签名时间,时间必须跟 Mixin 服务器时间基本一致,
"exp": 过期时间,建议不要设置太长,3 分钟足够,
"jti": 请求的唯一 ID,必须使用标准的 UUID 格式,
"sig": sha256(method+URI+body),
此后对所有的 API 访问包含上面签名过的 JWT token 做为一个 Bearer Authorization HTTP header。
*注意:这里是 APP 的 ACCESS_TOKEN *
每个用户都是由一个标准的 RSA 密钥代表的,首先需要在本地生成一对 RSA 的密钥,并保存好 PRIVATE KEY,然后将 PUBLIC KEY 以 Base64 Encode 的形式做为相应参数(session_secret)发送给 Mixin 服务器节点,同时可选的发送一个用户名字来方便区分用户。
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/users
{ "session_secret": Base64 of RSA PUBLIC KEY, "full_name": 可选的用来方便区分用户的名字, }
=>
{ "data": { "type": "user", "user_id": UUID, "session_id": UUID, "pin_token": RSA PRIVATE KEY, ... } }
每个 Mixin 的用户都需要有一个 PIN 码,转帐要用。创建新用户的时候是不包含这个密码的,所以需要更新。
注意:这里的 ACCESS_TOKEN 跟 1 中的加密方式一致,但是是用 2 中用户的信息(相当于对每个独立的用户进行的操作)
curl -X POXT -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/pin/update
{ "old_pin": "", // 默认值是空 "pin": "encrypted_pin", // 加密的 pin }
如何得到加密的 PIN
- 服务器返回的 pin_token 解密,得到 key
- 得到一个 pin + LittleEndian(time) + iterator (每次加密都要加 1)
- 进行 AES 加密
func testEncryptPIN(ctx context.Context, pin, pinToken, sessionId string, key *rsa.PrivateKey, iterator uint64) string {
token, _ := base64.StdEncoding.DecodeString(pinToken)
keyBytes, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, key, token, []byte(sessionId))
if err != nil {
return ""
}
pinByte := []byte(pin)
timeBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(timeBytes, uint64(time.Now().Unix()))
pinByte = append(pinByte, timeBytes...)
iteratorBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(iteratorBytes, iterator)
pinByte = append(pinByte, iteratorBytes...)
padding := aes.BlockSize - len(pinByte)%aes.BlockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
pinByte = append(pinByte, padtext...)
block, _ := aes.NewCipher(keyBytes)
ciphertext := make([]byte, aes.BlockSize+len(pinByte))
iv := ciphertext[:aes.BlockSize]
io.ReadFull(rand.Reader, iv)
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], pinByte)
return base64.StdEncoding.EncodeToString(ciphertext)
}
每个用户都拥有所有货币 asset 的充值地址,必须通过下面的 API 访问来获取相应 asset 的信息,其中的 public_key 字段为用户的充值地址。
*注意:这里是用户的 ACCESS_TOKEN *
curl -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/assets/UUID
=>
{ "data": { "type": "asset", "asset_id": UUID, "public_key": Adress, ... } }
现在支持的 asset UUID 有两种,BTC 和 ETH,其中 ETH 的地址可以自动支持所有 ERC20 资产的充值。
BTC c6d0c728-2624-429b-8e0d-d9d19b6592fa ETH 43d61dcd-e413-450d-80b8-101d5e903357
注意:ACCESS_TOKEN 是土豪的
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/transfers
{ "asset_id": "", // 默认值是空 "counter_user_id": UUID, // 主播的 "amount": "amount", "pin": "encrypted_pin", // 加密的 pin "trace_id": UUID, // 可以随时用这个 id 来查询转帐的记录 "memo": "备注", }
=>
{ "type": "transfer", "snapshot_id": UUID, "trace_id": UUID, ... }
注意: ACCESS_TOKEN 属于用户
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/addresses
{ "asset_id" : UUID, "public_key": "ETH OR BTC", "label": "备注", "pin": "encrypted_pin", // 加密的 pin }
=>
{ "type": "address", "address_id": UUID, "asset_id": UUID, "public_key": "ETH OR BTC", ... }
注意: ACCESS_TOKEN 属于用户
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" https://api.mixin.one/withdrawals
{ "address_id": UUID, // 提现的地址 "amount": "amount", "pin": "encrypted_pin", // 加密的 pin "trace_id": UUID, // 可以随时用这个 id 来查询转帐的记录 "memo": "备注", }
=>
{ "type": "withdrawal", "snapshot_id": UUID, "trace_id": UUID, ... }