contracts.nft.nft-collection.fc Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smartcontract Show documentation
Show all versions of smartcontract Show documentation
Build and manipulate TON smart contracts in easy way.
;; 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;
(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 src: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 ();
}
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(workchain(), 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());
}