mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-15 04:32:21 +00:00
* Add legacy_tester for existing funC contracts * Add storage-contracts and pragma options
173 lines
6.1 KiB
Text
173 lines
6.1 KiB
Text
;; NFT collection smart contract
|
|
|
|
;; storage scheme
|
|
;; default#_ royalty_factor:uint16 royalty_base:uint16 royalty_address:MsgAddress = RoyaltyParams;
|
|
;; storage#_ owner_address:MsgAddress next_item_index:uint64
|
|
;; ^[collection_content:^Cell common_content:^Cell]
|
|
;; nft_item_code:^Cell
|
|
;; royalty_params:^RoyaltyParams
|
|
;; = Storage;
|
|
|
|
#include "op-codes.fc";
|
|
#include "stdlib.fc";
|
|
#include "params.fc";
|
|
|
|
(slice, int, cell, cell, cell) load_data() inline {
|
|
var ds = get_data().begin_parse();
|
|
return
|
|
(ds~load_msg_addr(), ;; owner_address
|
|
ds~load_uint(64), ;; next_item_index
|
|
ds~load_ref(), ;; content
|
|
ds~load_ref(), ;; nft_item_code
|
|
ds~load_ref() ;; royalty_params
|
|
);
|
|
}
|
|
|
|
() save_data(slice owner_address, int next_item_index, cell content, cell nft_item_code, cell royalty_params) impure inline {
|
|
set_data(begin_cell()
|
|
.store_slice(owner_address)
|
|
.store_uint(next_item_index, 64)
|
|
.store_ref(content)
|
|
.store_ref(nft_item_code)
|
|
.store_ref(royalty_params)
|
|
.end_cell());
|
|
}
|
|
|
|
cell calculate_nft_item_state_init(int item_index, cell nft_item_code) {
|
|
cell data = begin_cell().store_uint(item_index, 64).store_slice(my_address()).end_cell();
|
|
return begin_cell().store_uint(0, 2).store_dict(nft_item_code).store_dict(data).store_uint(0, 1).end_cell();
|
|
}
|
|
|
|
slice calculate_nft_item_address(int wc, cell state_init) {
|
|
return begin_cell().store_uint(4, 3)
|
|
.store_int(wc, 8)
|
|
.store_uint(cell_hash(state_init), 256)
|
|
.end_cell()
|
|
.begin_parse();
|
|
}
|
|
|
|
() deploy_nft_item(int item_index, cell nft_item_code, int amount, cell nft_content) impure {
|
|
cell state_init = calculate_nft_item_state_init(item_index, nft_item_code);
|
|
slice nft_address = calculate_nft_item_address(workchain(), state_init);
|
|
var msg = begin_cell()
|
|
.store_uint(0x18, 6)
|
|
.store_slice(nft_address)
|
|
.store_coins(amount)
|
|
.store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
|
|
.store_ref(state_init)
|
|
.store_ref(nft_content);
|
|
send_raw_message(msg.end_cell(), 1); ;; pay transfer fees separately, revert on errors
|
|
}
|
|
|
|
() send_royalty_params(slice to_address, int query_id, slice data) impure inline {
|
|
var msg = begin_cell()
|
|
.store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool packages:MsgAddress -> 011000
|
|
.store_slice(to_address)
|
|
.store_coins(0)
|
|
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
|
.store_uint(op::report_royalty_params(), 32)
|
|
.store_uint(query_id, 64)
|
|
.store_slice(data);
|
|
send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message
|
|
}
|
|
|
|
() recv_internal(cell in_msg_full, slice in_msg_body) impure {
|
|
if (in_msg_body.slice_empty?()) { ;; ignore empty messages
|
|
return ();
|
|
}
|
|
slice cs = in_msg_full.begin_parse();
|
|
int flags = cs~load_uint(4);
|
|
|
|
if (flags & 1) { ;; ignore all bounced messages
|
|
return ();
|
|
}
|
|
slice sender_address = cs~load_msg_addr();
|
|
|
|
int op = in_msg_body~load_uint(32);
|
|
int query_id = in_msg_body~load_uint(64);
|
|
|
|
var (owner_address, next_item_index, content, nft_item_code, royalty_params) = load_data();
|
|
|
|
if (op == op::get_royalty_params()) {
|
|
send_royalty_params(sender_address, query_id, royalty_params.begin_parse());
|
|
return ();
|
|
}
|
|
|
|
throw_unless(401, equal_slices(sender_address, owner_address));
|
|
|
|
|
|
if (op == 1) { ;; deploy new nft
|
|
int item_index = in_msg_body~load_uint(64);
|
|
throw_unless(402, item_index <= next_item_index);
|
|
var is_last = item_index == next_item_index;
|
|
deploy_nft_item(item_index, nft_item_code, in_msg_body~load_coins(), in_msg_body~load_ref());
|
|
if (is_last) {
|
|
next_item_index += 1;
|
|
save_data(owner_address, next_item_index, content, nft_item_code, royalty_params);
|
|
}
|
|
return ();
|
|
}
|
|
if (op == 2) { ;; batch deploy of new nfts
|
|
int counter = 0;
|
|
cell deploy_list = in_msg_body~load_ref();
|
|
do {
|
|
var (item_index, item, f?) = deploy_list~udict::delete_get_min(64);
|
|
if (f?) {
|
|
counter += 1;
|
|
if (counter >= 250) { ;; Limit due to limits of action list size
|
|
throw(399);
|
|
}
|
|
|
|
throw_unless(403 + counter, item_index <= next_item_index);
|
|
deploy_nft_item(item_index, nft_item_code, item~load_coins(), item~load_ref());
|
|
if (item_index == next_item_index) {
|
|
next_item_index += 1;
|
|
}
|
|
}
|
|
} until ( ~ f?);
|
|
save_data(owner_address, next_item_index, content, nft_item_code, royalty_params);
|
|
return ();
|
|
}
|
|
if (op == 3) { ;; change owner
|
|
slice new_owner = in_msg_body~load_msg_addr();
|
|
save_data(new_owner, next_item_index, content, nft_item_code, royalty_params);
|
|
return ();
|
|
}
|
|
if (op == 4) { ;; change content
|
|
save_data(owner_address, next_item_index, in_msg_body~load_ref(), nft_item_code, in_msg_body~load_ref());
|
|
return ();
|
|
}
|
|
throw(0xffff);
|
|
}
|
|
|
|
;; Get methods
|
|
|
|
(int, cell, slice) get_collection_data() method_id {
|
|
var (owner_address, next_item_index, content, _, _) = load_data();
|
|
slice cs = content.begin_parse();
|
|
return (next_item_index, cs~load_ref(), owner_address);
|
|
}
|
|
|
|
slice get_nft_address_by_index(int index) method_id {
|
|
var (_, _, _, nft_item_code, _) = load_data();
|
|
cell state_init = calculate_nft_item_state_init(index, nft_item_code);
|
|
return calculate_nft_item_address(0, state_init);
|
|
}
|
|
|
|
(int, int, slice) royalty_params() method_id {
|
|
var (_, _, _, _, royalty) = load_data();
|
|
slice rs = royalty.begin_parse();
|
|
return (rs~load_uint(16), rs~load_uint(16), rs~load_msg_addr());
|
|
}
|
|
|
|
cell get_nft_content(int index, cell individual_nft_content) method_id {
|
|
var (_, _, content, _, _) = load_data();
|
|
slice cs = content.begin_parse();
|
|
cs~load_ref();
|
|
slice common_content = cs~load_ref().begin_parse();
|
|
return (begin_cell()
|
|
.store_uint(1, 8) ;; offchain tag
|
|
.store_slice(common_content)
|
|
.store_ref(individual_nft_content)
|
|
.end_cell());
|
|
}
|