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 "Asset.h"
8

9
#include <boost/algorithm/string/trim.hpp>
10
#include <boost/lexical_cast.hpp>
11
#include <stdexcept>
12

13
using namespace TW::EOS;
14

15
static const int64_t Precision = 1000;
16
static const uint8_t MaxDecimals = 18;
17

18 1
Asset::Asset(int64_t amount, uint8_t decimals, const std::string& symbol) {
19 1
    if (decimals > MaxDecimals) {
20 0
        throw std::invalid_argument("Too many decimals!");
21
    }
22 1
    this->symbol |= decimals;
23

24 1
    if (symbol.size() < 1 || symbol.size() > 7) {
25 0
        throw std::invalid_argument("Symbol size invalid!");
26
    }
27

28 1
    for (int i = 0; i < symbol.size(); i++) {
29 1
        uint64_t c = symbol[i];
30 1
        if (c < 'A' || c > 'Z') {
31 0
            throw std::invalid_argument("Invalid symbol " + symbol + ".\n Symbol can only have upper case alphabets!");
32
        }
33

34 1
        this->symbol |= c << (8 * (i + 1));
35
    }
36

37 1
    this->amount = amount;
38
}
39

40 1
Asset Asset::fromString(std::string assetString) {
41
    using namespace std;
42

43 1
    boost::algorithm::trim(assetString);
44

45
    // Find space in order to split amount and symbol
46 1
    auto spacePosition = assetString.find(' ');
47 1
    if (spacePosition == string::npos) {
48 0
        throw std::invalid_argument("Asset's amount and symbol should be separated with space");
49
    }
50

51 1
    auto symbolString = boost::algorithm::trim_copy(assetString.substr(spacePosition + 1));
52 1
    auto amountString = assetString.substr(0, spacePosition);
53

54
    // Ensure that if decimal point is used (.), decimal fraction is specified
55 1
    auto dotPosition = amountString.find('.');
56 1
    if (dotPosition != string::npos && dotPosition == amountString.size() - 1) {
57 0
        throw std::invalid_argument("Missing decimal fraction after decimal point");
58
    }
59

60 1
    uint8_t decimals = 0;
61 1
    if (dotPosition != string::npos) {
62 1
        decimals = static_cast<uint8_t>(amountString.size() - dotPosition - 1);
63
    }
64
                           
65 1
    int64_t precision = static_cast<uint64_t>(pow(10, static_cast<double>(decimals)));
66

67
    // Parse amount
68 1
    int64_t intPart, fractPart = 0;
69 1
    if (dotPosition != string::npos) {
70 1
        intPart = boost::lexical_cast<int64_t>(amountString.data(), dotPosition);
71 1
        fractPart = boost::lexical_cast<int64_t>(amountString.data() + dotPosition + 1, decimals);
72 1
        if (amountString[0] == '-') {
73 1
            fractPart *= -1;
74
        }
75 1
    } else {
76 0
        intPart = boost::lexical_cast<int64_t>(amountString);
77
    }
78

79 1
    int64_t amount = intPart;
80

81
    // multiply and check overflow
82 1
    amount *= precision;
83 1
    if (amount / precision != intPart) {
84 0
        throw std::invalid_argument("Amount too large!");
85
    }
86

87
    // add and check overflow
88 1
    amount += fractPart;
89 1
    if (amountString[0] == '-') {
90 1
        if (amount > fractPart) {
91 0
            throw std::invalid_argument("Amount too large!");
92
        }
93 1
    } else {
94 1
        if (amount < fractPart) {
95 0
            throw std::invalid_argument("Amount too large!");
96
        }
97
    }
98

99 1
    return Asset(amount, decimals, symbolString);
100
}
101

102 1
void Asset::serialize(Data& os) const noexcept {
103 1
    encode64LE(amount, os);
104 1
    encode64LE(symbol, os);
105
}
106

107 1
std::string Asset::string() const {
108
    static const int maxBufferSize = 30;
109
    char buffer[maxBufferSize];
110

111 1
    auto decimals = getDecimals();
112

113 1
    int charsWritten = snprintf(buffer, maxBufferSize, "%.*f %s", 
114 1
                            decimals, 
115 1
                            static_cast<double>(amount) / Precision,
116 1
                            getSymbol().c_str());
117

118 1
    if (charsWritten < 0 || charsWritten > maxBufferSize) {
119 0
        throw std::runtime_error("Failed to create string representation of asset!");
120
    }
121

122 1
    return std::string(buffer, charsWritten);
123
}
124

125 1
std::string Asset::getSymbol() const noexcept {
126 1
    uint64_t temp = symbol >> 8;
127 1
    std::string str;
128

129 1
    while (temp > 0) {
130 1
        str += temp & 0xFF;
131 1
        temp >>= 8;
132
    }
133

134 1
    return str;
135
}

Read our documentation on viewing source code .

Loading