-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathTransaction.h
219 lines (193 loc) · 7.63 KB
/
Transaction.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.
#pragma once
#include "Address.h"
#include "XAddress.h"
#include "Data.h"
#include "../proto/Ripple.pb.h"
#include "../HexCoding.h"
namespace TW::Ripple {
// See https://github.com/XRPLF/rippled/blob/master/src/ripple/protocol/SField.h#L57-L74
enum class FieldType: int {
int16 = 1,
int32 = 2,
hash256 = 5,
amount = 6,
vl = 7,
account = 8,
vector256 = 19
};
// See https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/enums/definitions.json
enum class TransactionType {
no_type = -1,
payment = 0,
EscrowCreate = 1,
EscrowFinish = 2,
EscrowCancel = 4,
TrustSet = 20,
NFTokenBurn = 26,
NFTokenCreateOffer = 27,
NFTokenCancelOffer = 28,
NFTokenAcceptOffer = 29
};
// See https://xrpl.org/nftokencreateoffer.html
enum class NFTokenCreateOfferFlags: int64_t {
tfSellNFToken = 0x00000001
};
class Transaction {
/// Float and negative amounts are not supported.
/// See https://github.com/trezor/trezor-core/tree/master/src/apps/ripple#transactions
public:
struct CurrencyAmount {
std::string currency;
Data value;
Data issuer;
};
int64_t amount;
CurrencyAmount currency_amount;
CurrencyAmount limit_amount;
int64_t fee;
int64_t flags;
int32_t sequence;
int32_t last_ledger_sequence;
Address account;
Data destination;
bool encode_tag;
int64_t destination_tag;
Data pub_key;
Data signature;
int64_t cancel_after;
int64_t finish_after;
Data owner;
int32_t offer_sequence;
Data condition;
Data fulfillment;
Data nftoken_id;
Data sell_offer;
Data token_offers;
TransactionType transaction_type;
Transaction(int64_t fee, int64_t flags, int32_t sequence, int32_t last_ledger_sequence, Address p_account)
: amount(0)
, fee(fee)
, flags(flags)
, sequence(sequence)
, last_ledger_sequence(last_ledger_sequence)
, account(p_account)
, encode_tag(false)
, destination_tag(0)
, cancel_after(0)
, finish_after(0)
, offer_sequence(0)
, nftoken_id(0)
, sell_offer(0)
, token_offers(0)
, transaction_type(TransactionType::no_type) {}
void createXrpPayment(int64_t p_amount, const std::string& p_destination, int64_t p_destination_tag) {
transaction_type = TransactionType::payment;
amount = p_amount;
setDestination(p_destination, p_destination_tag);
}
void createTrustSet(const std::string& currency, const std::string& issuer) {
// Use maximum amount
// https://xrpl.org/currency-formats.html
std::string value("9999999999999999e80");
createTrustSet(currency, value, issuer);
}
void createTrustSet(const std::string& currency, const std::string& value, const std::string& issuer) {
transaction_type = TransactionType::TrustSet;
setCurrencyAmount(limit_amount, currency, value, issuer);
}
void createTokenPayment(const std::string& currency, const std::string& value, const std::string& issuer,
const std::string& p_destination, int64_t p_destination_tag) {
transaction_type = TransactionType::payment;
setDestination(p_destination, p_destination_tag);
setCurrencyAmount(currency_amount, currency, value, issuer);
}
void createEscrowCreate(int64_t amount, const std::string& destination, int64_t destination_tag,
int64_t cancel_after, int64_t finish_after, const std::string& condition) {
transaction_type = TransactionType::EscrowCreate;
if (cancel_after == 0 && finish_after == 0) {
throw std::invalid_argument("Either CancelAfter or FinishAfter must be specified");
} else if (finish_after == 0 && condition.length() == 0) {
throw std::invalid_argument("Either Condition or FinishAfter must be specified");
}
this->amount = amount;
setDestination(destination, destination_tag);
this->cancel_after = cancel_after;
this->finish_after = finish_after;
this->condition = parse_hex(condition);
}
void createEscrowCancel(const std::string& owner, int32_t offer_sequence) {
transaction_type = TransactionType::EscrowCancel;
setAccount(owner, this->owner);
this->offer_sequence = offer_sequence;
}
void createEscrowFinish(const std::string& owner, int32_t offer_sequence,
const std::string& condition, const std::string& fulfillment) {
transaction_type = TransactionType::EscrowFinish;
setAccount(owner, this->owner);
this->offer_sequence = offer_sequence;
this->condition = parse_hex(condition);
this->fulfillment = parse_hex(fulfillment);
}
void createNFTokenBurn(const std::string& p_nftoken_id) {
transaction_type = TransactionType::NFTokenBurn;
nftoken_id = parse_hex(p_nftoken_id);
}
void createNFTokenCreateOffer(const std::string& p_nftoken_id, const std::string& p_destination) {
transaction_type = TransactionType::NFTokenCreateOffer;
flags = int64_t(NFTokenCreateOfferFlags::tfSellNFToken);
nftoken_id = parse_hex(p_nftoken_id);
setAccount(p_destination, destination);
}
void createNFTokenAcceptOffer(const std::string& p_sell_offer) {
transaction_type = TransactionType::NFTokenAcceptOffer;
sell_offer = parse_hex(p_sell_offer);
}
void createNFTokenCancelOffer(const std::vector<std::string> p_token_offers) {
transaction_type = TransactionType::NFTokenCancelOffer;
for (auto i : p_token_offers) {
Data token_offer = parse_hex(i);
token_offers.insert(token_offers.end(), token_offer.begin(), token_offer.end());
}
}
public:
/// simplified serialization format tailored for Payment transaction type
/// exclusively.
Data serialize() const;
Data getPreImage() const;
static Data serializeAmount(int64_t amount);
static Data serializeCurrencyAmount(const CurrencyAmount& currency_amount);
static Data serializeAddress(Address address);
static void serializeCurrencyCode(Data& out, const std::string& currency_code);
private:
void setCurrencyAmount(CurrencyAmount& p_currency_amount, const std::string& p_currency, const std::string& value, const std::string& issuer) {
p_currency_amount.currency = p_currency;
p_currency_amount.value = Data(value.begin(), value.end());
setAccount(issuer, p_currency_amount.issuer);
}
void setDestination(const std::string& p_destination, int64_t p_destination_tag) {
try {
auto address = Address(p_destination);
encode_tag = p_destination_tag > 0;
destination_tag = p_destination_tag;
destination = Data(address.bytes.begin() + 1, address.bytes.end());
} catch(const std::exception& e) {
auto xAddress = XAddress(p_destination);
encode_tag = xAddress.flag != TagFlag::none;
destination_tag = xAddress.tag;
destination = Data(xAddress.bytes.begin(), xAddress.bytes.end());
}
}
void setAccount(const std::string& p_account, Data& data) {
try {
auto address = Address(p_account);
data = Data(address.bytes.begin() + 1, address.bytes.end());
} catch(const std::exception& e) {
auto xAddress = XAddress(p_account);
data = Data(xAddress.bytes.begin(), xAddress.bytes.end());
}
}
};
} // namespace TW::Ripple