-
Notifications
You must be signed in to change notification settings - Fork 2
/
RootTokenContractNF.cpp
204 lines (161 loc) · 6.75 KB
/
RootTokenContractNF.cpp
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
#include "RootTokenContractNF.hpp"
#include "TONTokenWalletNF.hpp"
#include <tvm/contract.hpp>
#include <tvm/smart_switcher.hpp>
#include <tvm/smart_contract_info.hpp>
#include <tvm/contract_handle.hpp>
#include <tvm/default_support_functions.hpp>
using namespace tvm;
using namespace schema;
static constexpr unsigned ROOT_TIMESTAMP_DELAY = 100;
class RootTokenContract final : public smart_interface<IRootTokenContract>, public DRootTokenContract {
public:
using root_replay_protection_t = replay_attack_protection::timestamp<ROOT_TIMESTAMP_DELAY>;
struct error_code : tvm::error_code {
static constexpr unsigned message_sender_is_not_my_owner = 100;
static constexpr unsigned token_not_minted = 101;
static constexpr unsigned wrong_bounced_header = 102;
static constexpr unsigned wrong_bounced_args = 103;
static constexpr unsigned wrong_mint_token_id = 104;
static constexpr unsigned not_enough_balance = 105;
};
__always_inline
void constructor(bytes name, bytes symbol, uint8 decimals, uint256 root_public_key, cell wallet_code) {
name_ = name;
symbol_ = symbol;
decimals_ = decimals;
root_public_key_ = root_public_key;
wallet_code_ = wallet_code;
total_supply_ = TokensType(0);
total_granted_ = TokensType(0);
// struct t_file p1 = {name,uint_t<8>{0},name};
// files_ = p1;
}
__always_inline
lazy<MsgAddressInt> deployWallet(int8 workchain_id, uint256 pubkey, TokenId tokenId, WalletGramsType grams, lazy<MsgAddressInt> nonce) {
require(root_public_key_ == tvm_pubkey(), error_code::message_sender_is_not_my_owner);
require(!tokenId || tokens_.contains(tokenId), error_code::token_not_minted);
tvm_accept();
auto [wallet_init, dest] = calc_wallet_init(workchain_id, pubkey,nonce); // maybe change time to msg.sender
contract_handle<ITONTokenWallet> dest_handle(dest);
dest_handle.deploy(wallet_init, Grams(grams.get())).
call<&ITONTokenWallet::accept>(tokenId);
if (tokenId)
++total_granted_;
return dest;
}
__always_inline
lazy<MsgAddressInt> deployWallet_response(int8 workchain_id, uint256 pubkey, WalletGramsType grams, lazy<MsgAddressInt> nonce) {
auto value = int_value();
require(value() >= 500000000 + grams.get(), error_code::not_enough_balance);
tvm_accept();
auto [wallet_init, dest] = calc_wallet_init(workchain_id, pubkey,nonce);
contract_handle<ITONTokenWallet> dest_handle(dest);
dest_handle.deploy(wallet_init, Grams(grams.get())).
call<&ITONTokenWallet::accept>(TokenId(0));
set_int_return_flag(0);
set_int_return_value(100000000);
return dest;
}
__always_inline
void grant(lazy<MsgAddressInt> dest, TokenId tokenId, WalletGramsType grams) {
require(root_public_key_ == tvm_pubkey(), error_code::message_sender_is_not_my_owner);
require(tokens_.contains(tokenId), error_code::token_not_minted);
tvm_accept();
contract_handle<ITONTokenWallet> dest_handle(dest);
dest_handle(Grams(grams.get())).call<&ITONTokenWallet::accept>(tokenId);
++total_granted_;
}
__always_inline
TokenId mint(TokenId tokenId, bytes name, bytes jsonMeta,lazy<MsgAddressInt> data) {
require(root_public_key_ == tvm_pubkey(), error_code::message_sender_is_not_my_owner);
require(tokenId == total_supply_ + 1, error_code::wrong_mint_token_id);
tvm_accept();
t_file file;
file.name = name;
file.time = uint_t<64>{smart_contract_info::now()};
file.data = data;
file.jsonMeta = jsonMeta;
files_.set_at(total_supply_.get(),file);
tokens_.insert(tokenId);
++total_supply_;
return tokenId;
}
// getters
__always_inline bytes getName() {
return name_;
}
__always_inline bytes getSymbol() {
return symbol_;
}
__always_inline uint8 getDecimals() {
return decimals_;
}
__always_inline uint256 getRootKey() {
return root_public_key_;
}
__always_inline TokensType getTotalSupply() {
return total_supply_;
}
__always_inline TokensType getTotalGranted() {
return total_granted_;
}
__always_inline cell getWalletCode() {
return wallet_code_;
}
__always_inline TokenId getLastMintedToken() {
return total_supply_;
}
__always_inline t_file getInfoToken(TokenId tokenId) {
return files_.get_at(tokenId.get() - 1);
}
__always_inline bytes getJson(TokenId tokenId) {
//return files_;
return files_.get_at(tokenId.get() - 1).jsonMeta;
}
__always_inline
lazy<MsgAddressInt> getWalletAddress(int8 workchain_id, uint256 pubkey, lazy<MsgAddressInt> nonce) {
return calc_wallet_init(workchain_id, pubkey,nonce).second;
}
// received bounced message back
__always_inline static int _on_bounced(cell msg, slice msg_body) {
tvm_accept();
using Args = args_struct_t<&ITONTokenWallet::accept>;
parser p(msg_body);
require(p.ldi(32) == -1, error_code::wrong_bounced_header);
auto [opt_hdr, =p] = parse_continue<abiv1::internal_msg_header>(p);
require(opt_hdr && opt_hdr->function_id == id_v<&ITONTokenWallet::accept>,
error_code::wrong_bounced_header);
auto args = parse<Args>(p, error_code::wrong_bounced_args);
auto bounced_id = args.tokenId;
auto [hdr, persist] = load_persistent_data<IRootTokenContract, root_replay_protection_t, DRootTokenContract>();
require(bounced_id > 0, error_code::wrong_bounced_args);
require(bounced_id <= persist.total_supply_, error_code::wrong_bounced_args);
require(persist.total_granted_ > 0, error_code::wrong_bounced_args);
--persist.total_granted_;
persist.tokens_.insert(bounced_id);
save_persistent_data<IRootTokenContract, root_replay_protection_t>(hdr, persist);
return 0;
}
//default processing of unknown messages
__always_inline static int _fallback(cell msg, slice msg_body) {
return 0;
}
// =============== Support functions ==================
DEFAULT_SUPPORT_FUNCTIONS(IRootTokenContract, root_replay_protection_t)
private:
__always_inline
std::pair<StateInit, lazy<MsgAddressInt>> calc_wallet_init(int8 workchain_id, uint256 pubkey, lazy<MsgAddressInt> nonce) {
DTONTokenWallet wallet_data {
name_, symbol_, decimals_,
root_public_key_, pubkey,
lazy<MsgAddressInt>{tvm_myaddr()}, wallet_code_, nonce, {}, {},
};
auto [wallet_init, dest_addr] = prepare_wallet_state_init_and_addr(wallet_data);
lazy<MsgAddressInt> dest{ MsgAddressInt{ addr_std { {}, {}, workchain_id, dest_addr } } };
return { wallet_init, dest };
}
};
DEFINE_JSON_ABI(IRootTokenContract, DRootTokenContract, ERootTokenContract);
// ----------------------------- Main entry functions ---------------------- //
DEFAULT_MAIN_ENTRY_FUNCTIONS(RootTokenContract, IRootTokenContract, DRootTokenContract, ROOT_TIMESTAMP_DELAY)