157 lines
5.6 KiB
Plaintext
157 lines
5.6 KiB
Plaintext
;;
|
|
;; TON NFT Item Smart Contract v2
|
|
;; support ownership_assigned on minting nft
|
|
;;
|
|
|
|
{-
|
|
|
|
NOTE that this tokens can be transferred within the same workchain.
|
|
|
|
This is suitable for most tokens, if you need tokens transferable between workchains there are two solutions:
|
|
|
|
1) use more expensive but universal function below to calculate message forward fee for arbitrary destination (see `misc/forward-fee-calc.cs`)
|
|
|
|
2) use token holder proxies in target workchain (that way even 'non-universal' token can be used from any workchain)
|
|
|
|
-}
|
|
|
|
#include "imports/stdlib.fc";
|
|
#include "imports/op-codes.fc";
|
|
#include "imports/params.fc";
|
|
|
|
int min_tons_for_storage() asm "50000000 PUSHINT"; ;; 0.05 TON
|
|
|
|
;;
|
|
;; Storage
|
|
;;
|
|
;; uint64 index
|
|
;; MsgAddressInt collection_address
|
|
;; MsgAddressInt owner_address
|
|
;; cell content
|
|
;;
|
|
|
|
(int, int, slice, slice, cell) load_data() {
|
|
slice ds = get_data().begin_parse();
|
|
var (index, collection_address) = (ds~load_uint(64), ds~load_msg_addr());
|
|
if (ds.slice_bits() > 0) {
|
|
return (-1, index, collection_address, ds~load_msg_addr(), ds~load_ref());
|
|
} else {
|
|
return (0, index, collection_address, null(), null()); ;; nft not initialized yet
|
|
}
|
|
}
|
|
|
|
() store_data(int index, slice collection_address, slice owner_address, cell content) impure {
|
|
set_data(
|
|
begin_cell()
|
|
.store_uint(index, 64)
|
|
.store_slice(collection_address)
|
|
.store_slice(owner_address)
|
|
.store_ref(content)
|
|
.end_cell()
|
|
);
|
|
}
|
|
|
|
() send_msg(slice to_address, int amount, int op, int query_id, builder payload, int send_mode) 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(amount)
|
|
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
|
|
.store_uint(op, 32)
|
|
.store_uint(query_id, 64);
|
|
|
|
if (~ builder_null?(payload)) {
|
|
msg = msg.store_builder(payload);
|
|
}
|
|
|
|
send_raw_message(msg.end_cell(), send_mode);
|
|
}
|
|
|
|
() transfer_ownership(int my_balance, int index, slice collection_address, slice owner_address, cell content, slice sender_address, int query_id, slice in_msg_body, int fwd_fees) impure inline {
|
|
throw_unless(401, equal_slices(sender_address, owner_address));
|
|
|
|
slice new_owner_address = in_msg_body~load_msg_addr();
|
|
force_chain(new_owner_address);
|
|
slice response_destination = in_msg_body~load_msg_addr();
|
|
in_msg_body~load_int(1); ;; this nft don't use custom_payload
|
|
int forward_amount = in_msg_body~load_coins();
|
|
|
|
int rest_amount = my_balance - min_tons_for_storage();
|
|
if (forward_amount) {
|
|
rest_amount -= (forward_amount + fwd_fees);
|
|
}
|
|
int need_response = response_destination.preload_uint(2) != 0; ;; if NOT addr_none: 00
|
|
if (need_response) {
|
|
rest_amount -= fwd_fees;
|
|
}
|
|
|
|
throw_unless(402, rest_amount >= 0); ;; base nft spends fixed amount of gas, will not check for response
|
|
|
|
if (forward_amount) {
|
|
send_msg(new_owner_address, forward_amount, op::ownership_assigned(), query_id, begin_cell().store_slice(owner_address).store_slice(in_msg_body), 1); ;; paying fees, revert on errors
|
|
}
|
|
if (need_response) {
|
|
force_chain(response_destination);
|
|
send_msg(response_destination, rest_amount, op::excesses(), query_id, null(), 1); ;; paying fees, revert on errors
|
|
}
|
|
|
|
store_data(index, collection_address, new_owner_address, content);
|
|
}
|
|
|
|
() recv_internal(int my_balance, int msg_value, 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();
|
|
|
|
cs~load_msg_addr(); ;; skip dst
|
|
cs~load_coins(); ;; skip value
|
|
cs~skip_bits(1); ;; skip extracurrency collection
|
|
cs~load_coins(); ;; skip ihr_fee
|
|
int fwd_fee = muldiv(cs~load_coins(), 3, 2); ;; we use message fwd_fee for estimation of forward_payload costs
|
|
|
|
|
|
(int init?, int index, slice collection_address, slice owner_address, cell content) = load_data();
|
|
if (~ init?) {
|
|
throw_unless(405, equal_slices(collection_address, sender_address));
|
|
var new_owner_address = in_msg_body~load_msg_addr();
|
|
store_data(index, collection_address, new_owner_address, in_msg_body~load_ref());
|
|
if (in_msg_body.slice_data_empty?() == false) {
|
|
var forward_amount = in_msg_body~load_coins();
|
|
if (forward_amount) {
|
|
send_msg(new_owner_address, forward_amount, op::ownership_assigned(), 0, begin_cell().store_slice(collection_address).store_slice(in_msg_body), 3); ;; paying fees, ignore errors
|
|
}
|
|
}
|
|
return ();
|
|
}
|
|
|
|
int op = in_msg_body~load_uint(32);
|
|
int query_id = in_msg_body~load_uint(64);
|
|
|
|
if (op == op::transfer()) {
|
|
transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, in_msg_body, fwd_fee);
|
|
return ();
|
|
}
|
|
if (op == op::get_static_data()) {
|
|
send_msg(sender_address, 0, op::report_static_data(), query_id, begin_cell().store_uint(index, 256).store_slice(collection_address), 64); ;; carry all the remaining value of the inbound message
|
|
return ();
|
|
}
|
|
throw(0xffff);
|
|
}
|
|
|
|
;;
|
|
;; GET Methods
|
|
;;
|
|
|
|
(int, int, slice, slice, cell) get_nft_data() method_id {
|
|
(int init?, int index, slice collection_address, slice owner_address, cell content) = load_data();
|
|
return (init?, index, collection_address, owner_address, content);
|
|
}
|