From 463e790ef74278b9f2cf120236591df3a2f2b46b Mon Sep 17 00:00:00 2001 From: igor Date: Tue, 27 Dec 2022 02:09:55 +0300 Subject: [PATCH] instant buy - first attempt --- contracts/imports/op-codes.fc | 1 + contracts/main.fc | 106 ++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/contracts/imports/op-codes.fc b/contracts/imports/op-codes.fc index f0685a5..16c2773 100644 --- a/contracts/imports/op-codes.fc +++ b/contracts/imports/op-codes.fc @@ -17,6 +17,7 @@ int op::editorship_assigned() asm "0x511a4463 PUSHINT"; ;; Collection int op::new_nft() asm "0x1a039a51 PUSHINT"; +int op::instant_buy_new_nft() asm "16c7d435 PUSHINT"; ;; DNS const int op::fill_up = 0x370fec51; diff --git a/contracts/main.fc b/contracts/main.fc index 5011fa6..1a5fdae 100644 --- a/contracts/main.fc +++ b/contracts/main.fc @@ -90,20 +90,35 @@ slice calculate_nft_item_address(int wc, cell state_init) { .begin_parse(); } +cell pack_state(cell content, cell nft_item_code, int index, slice collection_address, slice owner_address, cell domain, cell auction, int last_fill_up_time) impure { + return begin_cell() + .store_ref(nft_item_code) + .store_uint(index, 256) + .store_slice(collection_address) + .store_slice(owner_address) + .store_ref(content) + .store_ref(domain) + .store_dict(auction) + .store_uint(last_fill_up_time, 64) + .end_cell(); +} + ;; Serialize the data using the storage schema () store_data(cell content, cell nft_item_code, int index, slice collection_address, slice owner_address, cell domain, cell auction, int last_fill_up_time) impure { - set_data( - begin_cell() - .store_ref(nft_item_code) - .store_uint(index, 256) - .store_slice(collection_address) - .store_slice(owner_address) - .store_ref(content) - .store_ref(domain) - .store_dict(auction) - .store_uint(last_fill_up_time, 64) - .end_cell() - ); + ;; set_data( + ;; begin_cell() + ;; .store_ref(nft_item_code) + ;; .store_uint(index, 256) + ;; .store_slice(collection_address) + ;; .store_slice(owner_address) + ;; .store_ref(content) + ;; .store_ref(domain) + ;; .store_dict(auction) + ;; .store_uint(last_fill_up_time, 64) + ;; .end_cell() + ;; ); + + set_data(pack_state(content, nft_item_code, index, collection_address, owner_address, domain, auction, last_fill_up_time)); } () send_msg(slice to_address, int amount, int op, int query_id, builder payload, int send_mode) impure inline { @@ -186,6 +201,42 @@ slice calculate_nft_item_address(int wc, cell state_init) { send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message, fee deducted from amount } +cell pack_nft_item_state(cell nft_item_code, cell data) impure { + return begin_cell().store_uint(0, 2).store_dict(nft_item_code).store_dict(data).store_uint(0, 1).end_cell(); +} + +() deploy_bought_item(int item_index, cell code, slice owner_address, slice domain) impure { + ;; cell nft_item_code + ;; uint256 index --- The index of this item in the collection + ;; MsgAddressInt collection_address + ;; MsgAddressInt owner_address + ;; cell content --- The key-value map with the content both as item and a collection) + ;; cell domain --- e.g contains "alice" (without ending \0) for "alice.ton" domain + ;; cell auction --- auction info: (address max_bid_address, coins max_bid, uint32 end_time) + ;; int last_fill_up_time + cell init_data = begin_cell() + .store_ref(code) + .store_uint(item_index, 256) + .store_slice(my_address()) + .store_slice(owner_address) + .store_dict(null()) + .store_ref(begin_cell().store_uint(1, 1).store_slice(domain).end_cell()) ;; TODO: snake cell + .store_dict(null()) + .store_uint(0, 64) + .end_cell(); + + cell state_init = pack_nft_item_state(code, init_data); + slice nft_address = calculate_nft_item_address(workchain(), state_init); + var msg = begin_cell() + .store_uint(0x18, 6) + .store_slice(nft_address) + .store_coins(0) + .store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1) + .store_ref(state_init) + .store_uint(1, 1); ;; the content of the NFT item, will be treated as the parameter of the first incoming message + send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message, fee deducted from amount +} + () recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { if (in_msg_body.slice_empty?()) { ;; bounce back empty messages throw(0xffff); @@ -228,6 +279,10 @@ slice calculate_nft_item_address(int wc, cell state_init) { if (months > 12) { months = 12; } + + ;; move this to auction data: auction_start_time, auction_start_duration, auction_end_duration, auction_prolongation, price_multiplicator + ;; instant buy: + ;; The auction duration becomes shorter over time int duration = auction_start_duration - (auction_start_duration - auction_end_duration) * months / 12; @@ -259,6 +314,33 @@ slice calculate_nft_item_address(int wc, cell state_init) { store_data(content, item_code, index, collection_address, owner_address, domain, auction, last_fill_up_time); } + if (op == op::instant_buy_new_nft()) { + ;; parsing of the signed 'option' + ;; signature structure: (receiver_addr, collection_address, ) + cell option_data = in_msg_body~load_ref(); + cell signature = in_msg_body~load_ref(); + slice reader = option_data.begin_parse(); + + slice receiver_addr = reader~load_msg_addr(); + slice issued_collection_addr = reader~load_msg_addr(); + int amount = reader~load_uint(256); + slice new_domain = reader; + throw_unless(411, slice_bits(new_domain) > 0); + throw_unless(412, equal_slices(receiver_addr, sender_address)); ;; TODO: Unsure here + throw_unless(413, equal_slices(issued_collection_addr, my_address())); + int success = check_data_signature(option_data.begin_parse(), signature.begin_parse(), owner_address); + throw_unless(413, success); + throw_unless(414, msg_value > amount); + + amount_to_send = msg_value - amount; ;; TODO: Handle this later, reroute coins + + int new_item_index = slice_hash(new_domain); + deploy_bought_item(item_index, cell item_code, slice receiver_addr, slice new_domain); + return (); + + ;; init_state = pack_state(... add domain here ...) + ;; use modified function `deploy_nft_item` <- init_state + } if (op == op::new_nft()) { throw_unless(401, equal_slices(sender_address, owner_address)); ;; TODO (this is like the most important part)