1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#include "Signer.h"
8
#include "Serialization.h"
9
#include "../Hash.h"
10
#include "../HexCoding.h"
11
#include "../PrivateKey.h"
12

13
#include <google/protobuf/io/coded_stream.h>
14
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
15
#include <google/protobuf/util/json_util.h>
16

17
#include <string>
18

19
using namespace TW;
20
using namespace TW::Binance;
21

22
// Message prefixes
23
// see https://docs.binance.org/api-reference/transactions.html#amino-types
24 1
static const auto sendOrderPrefix = Data{0x2A, 0x2C, 0x87, 0xFA};
25 1
static const auto tradeOrderPrefix = Data{0xCE, 0x6D, 0xC0, 0x43};
26 1
static const auto cancelTradeOrderPrefix = Data{0x16, 0x6E, 0x68, 0x1B};
27 1
static const auto HTLTOrderPrefix = Data{0xB3, 0x3F, 0x9A, 0x24};
28 1
static const auto depositHTLTOrderPrefix = Data{0x63, 0x98, 0x64, 0x96};
29 1
static const auto claimHTLTOrderPrefix = Data{0xC1, 0x66, 0x53, 0x00};
30 1
static const auto refundHTLTOrderPrefix = Data{0x34, 0x54, 0xA2, 0x7C};
31 1
static const auto pubKeyPrefix = Data{0xEB, 0x5A, 0xE9, 0x87};
32 1
static const auto transactionPrefix = Data{0xF0, 0x62, 0x5D, 0xEE};
33 1
static const auto tokenIssueOrderPrefix = Data{0x17, 0xEF, 0xAB, 0x80};
34 1
static const auto tokenMintOrderPrefix = Data{0x46, 0x7E, 0x08, 0x29};
35 1
static const auto tokenBurnOrderPrefix = Data{0x7E, 0xD2, 0xD2, 0xA0};
36 1
static const auto tokenFreezeOrderPrefix = Data{0xE7, 0x74, 0xB3, 0x2D};
37 1
static const auto tokenUnfreezeOrderPrefix = Data{0x65, 0x15, 0xFF, 0x0D};
38 1
static const auto transferOutOrderPrefix = Data{0x80, 0x08, 0x19, 0xC0};
39 1
static const auto sideDelegateOrderPrefix = Data{0xE3, 0xA0, 0x7F, 0xD2};
40 1
static const auto sideRedelegateOrderPrefix = Data{0xE3, 0xCE, 0xD3, 0x64};
41 1
static const auto sideUndelegateOrderPrefix = Data{0x51, 0x4F, 0x7E, 0x0E};
42 1
static const auto timeLockOrderPrefix = Data{0x07, 0x92, 0x15, 0x31};
43 1
static const auto timeRelockOrderPrefix = Data{0x50, 0x47, 0x11, 0xDA};
44 1
static const auto timeUnlockOrderPrefix = Data{0xC4, 0x05, 0x0C, 0x6C};
45

46 1
Proto::SigningOutput Signer::sign(const Proto::SigningInput& input) noexcept {
47 1
    auto signer = Signer(input);
48 1
    auto encoded = signer.build();
49 1
    auto output = Proto::SigningOutput();
50 1
    output.set_encoded(encoded.data(), encoded.size());
51 1
    return output;
52
}
53

54 1
std::string Signer::signJSON(const std::string& json, const Data& key) {
55 1
    auto input = Proto::SigningInput();
56 1
    google::protobuf::util::JsonStringToMessage(json, &input);
57 1
    input.set_private_key(key.data(), key.size());
58 1
    auto output = Signer::sign(input);
59 1
    return hex(output.encoded());
60
}
61

62 1
Data Signer::build() const {
63 1
    auto signature = encodeSignature(sign());
64 1
    return encodeTransaction(signature);
65
}
66

67 1
Data Signer::sign() const {
68 1
    auto key = PrivateKey(input.private_key());
69 1
    auto hash = Hash::sha256(signaturePreimage());
70 1
    auto signature = key.sign(hash, TWCurveSECP256k1);
71 1
    return Data(signature.begin(), signature.end() - 1);
72
}
73

74 1
std::string Signer::signaturePreimage() const {
75 1
    auto json = signatureJSON(input);
76 1
    return json.dump();
77
}
78

79 1
Data Signer::encodeTransaction(const Data& signature) const {
80 1
    auto msg = encodeOrder();
81 1
    auto transaction = Binance::Proto::Transaction();
82 1
    transaction.add_msgs(msg.data(), msg.size());
83 1
    transaction.add_signatures(signature.data(), signature.size());
84 1
    transaction.set_memo(input.memo());
85 1
    transaction.set_source(input.source());
86

87 1
    auto data = transaction.SerializeAsString();
88 1
    return aminoWrap(data, transactionPrefix, true);
89
}
90

91 1
Data Signer::encodeOrder() const {
92 1
    std::string data;
93 1
    Data prefix;
94 1
    if (input.has_trade_order()) {
95 1
        data = input.trade_order().SerializeAsString();
96 1
        prefix = tradeOrderPrefix;
97 1
    } else if (input.has_cancel_trade_order()) {
98 0
        data = input.cancel_trade_order().SerializeAsString();
99 0
        prefix = cancelTradeOrderPrefix;
100 1
    } else if (input.has_send_order()) {
101 1
        data = input.send_order().SerializeAsString();
102 1
        prefix = sendOrderPrefix;
103 1
    } else if (input.has_issue_order()) {
104 1
        data = input.issue_order().SerializeAsString();
105 1
        prefix = tokenIssueOrderPrefix;
106 1
    } else if (input.has_mint_order()) {
107 1
        data = input.mint_order().SerializeAsString();
108 1
        prefix = tokenMintOrderPrefix;
109 1
    } else if (input.has_burn_order()) {
110 1
        data = input.burn_order().SerializeAsString();
111 1
        prefix = tokenBurnOrderPrefix;
112 1
    } else if (input.has_freeze_order()) {
113 1
        data = input.freeze_order().SerializeAsString();
114 1
        prefix = tokenFreezeOrderPrefix;
115 1
    } else if (input.has_unfreeze_order()) {
116 1
        data = input.unfreeze_order().SerializeAsString();
117 1
        prefix = tokenUnfreezeOrderPrefix;
118 1
    } else if (input.has_htlt_order()) {
119 1
        data = input.htlt_order().SerializeAsString();
120 1
        prefix = HTLTOrderPrefix;
121 1
    } else if (input.has_deposithtlt_order()) {
122 1
        data = input.deposithtlt_order().SerializeAsString();
123 1
        prefix = depositHTLTOrderPrefix;
124 1
    } else if (input.has_claimhtlt_order()) {
125 1
        data = input.claimhtlt_order().SerializeAsString();
126 1
        prefix = claimHTLTOrderPrefix;
127 1
    } else if (input.has_refundhtlt_order()) {
128 1
        data = input.refundhtlt_order().SerializeAsString();
129 1
        prefix = refundHTLTOrderPrefix;
130 1
    } else if (input.has_transfer_out_order()) {
131 1
        data = input.transfer_out_order().SerializeAsString();
132 1
        prefix = transferOutOrderPrefix;
133 1
    } else if (input.has_side_delegate_order()) {
134 1
        data = input.side_delegate_order().SerializeAsString();
135 1
        prefix = sideDelegateOrderPrefix;
136 1
    } else if (input.has_side_redelegate_order()) {
137 1
        data = input.side_redelegate_order().SerializeAsString();
138 1
        prefix = sideRedelegateOrderPrefix;
139 1
    } else if (input.has_side_undelegate_order()) {
140 1
        data = input.side_undelegate_order().SerializeAsString();
141 1
        prefix = sideUndelegateOrderPrefix;
142 1
    } else if (input.has_time_lock_order()) {
143 1
        data = input.time_lock_order().SerializeAsString();
144 1
        prefix = timeLockOrderPrefix;
145 1
    } else if (input.has_time_relock_order()) {
146 1
        data = input.time_relock_order().SerializeAsString();
147 1
        prefix = timeRelockOrderPrefix;
148 1
    } else if (input.has_time_unlock_order()) {
149 1
        data = input.time_unlock_order().SerializeAsString();
150 1
        prefix = timeUnlockOrderPrefix;
151 1
    } else {
152 0
        return {};
153
    }
154 1
    return aminoWrap(data, prefix, false);
155
}
156

157 1
Data Signer::encodeSignature(const Data& signature) const {
158 1
    auto key = PrivateKey(input.private_key());
159 1
    auto publicKey = key.getPublicKey(TWPublicKeyTypeSECP256k1);
160

161 1
    auto encodedPublicKey = pubKeyPrefix;
162 1
    encodedPublicKey.insert(encodedPublicKey.end(), static_cast<uint8_t>(publicKey.bytes.size()));
163 1
    encodedPublicKey.insert(encodedPublicKey.end(), publicKey.bytes.begin(), publicKey.bytes.end());
164

165 1
    auto object = Binance::Proto::Signature();
166 1
    object.set_pub_key(encodedPublicKey.data(), encodedPublicKey.size());
167 1
    object.set_signature(signature.data(), signature.size());
168 1
    object.set_account_number(input.account_number());
169 1
    object.set_sequence(input.sequence());
170

171 1
    return aminoWrap(object.SerializeAsString(), {}, false);
172
}
173

174 1
Data Signer::aminoWrap(const std::string& raw, const Data& typePrefix, bool prefixWithSize) const {
175 1
    const auto contentsSize = raw.size() + typePrefix.size();
176 1
    auto size = contentsSize;
177 1
    if (prefixWithSize) {
178 1
        size += 10;
179
    }
180

181 1
    std::string msg;
182 1
    msg.reserve(size);
183
    {
184 1
        google::protobuf::io::StringOutputStream output(&msg);
185 1
        google::protobuf::io::CodedOutputStream cos(&output);
186 1
        if (prefixWithSize) {
187 1
            cos.WriteVarint64(contentsSize);
188
        }
189 1
        cos.WriteRaw(typePrefix.data(), static_cast<int>(typePrefix.size()));
190 1
        cos.WriteRaw(raw.data(), static_cast<int>(raw.size()));
191
    }
192

193 1
    return Data(msg.begin(), msg.end());
194
}

Read our documentation on viewing source code .

Loading