You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
5.6 KiB
161 lines
5.6 KiB
;; DNS resolver smart contract (implements NFT Collection interface) |
|
#include "imports/dns-utils.fc"; |
|
#include "imports/op-codes.fc"; |
|
#include "imports/params.fc"; |
|
|
|
;; -1 if needed, 0 if not |
|
const signature_needed = 0; |
|
|
|
;; storage scheme |
|
;; cell collection_content |
|
;; cell nft_item_code |
|
;; cell pricing |
|
;; uint256(key) owner_key |
|
;; address owner_address |
|
|
|
(cell, cell, cell, int, slice) load_data() inline { |
|
var ds = get_data().begin_parse(); |
|
return ( |
|
ds~load_ref(), ;; content |
|
ds~load_ref(), ;; nft_item_code |
|
ds~load_ref(), ;; pricing |
|
ds~load_uint(256), ;; owner key |
|
ds~load_msg_addr() ;; owner address |
|
); |
|
} |
|
|
|
() save_data(cell content, cell nft_item_code, cell pricing, int owner_key, slice owner_addr) impure inline { |
|
set_data(begin_cell() |
|
.store_ref(content) |
|
.store_ref(nft_item_code) |
|
.store_ref(pricing) |
|
.store_uint(owner_key, 256) |
|
.store_slice(owner_addr) |
|
.end_cell()); |
|
} |
|
|
|
;; Calculate the price and check validness (otherwise throw exceptions) |
|
int calcprice(slice domain, cell pricing) inline_ref { |
|
int len = slice_bits(domain); |
|
throw_unless(200, len > 3 * 8); ;; minimum 4 characters |
|
throw_unless(201, len <= 126 * 8); ;; maxmimum 126 characters |
|
throw_unless(202, mod(len, 8) == 0); |
|
throw_unless(203, check_domain_string(domain)); |
|
return 100000; ;; todo |
|
} |
|
|
|
cell calculate_nft_item_state_init(int item_index, cell nft_item_code) { |
|
cell data = begin_cell().store_uint(item_index, 256).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, 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(0) |
|
.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(), 64); ;; carry all the remaining value of the inbound message, fee deducted from amount |
|
} |
|
|
|
int verify_signature(slice signature, slice sender_address, slice domain, int owner_key) { |
|
cell option_data = begin_cell().store_slice(my_address()).store_slice(domain).store_slice(sender_address).end_cell(); |
|
return check_signature(slice_hash(option_data.begin_parse()), signature, owner_key); |
|
} |
|
|
|
() 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); |
|
} |
|
slice cs = in_msg_full.begin_parse(); |
|
int flags = cs~load_uint(4); |
|
|
|
if (flags & 1) { ;; ignore all bounced messages |
|
return (); |
|
} |
|
|
|
int op = in_msg_body~load_uint(32); |
|
|
|
var (content, nft_item_code, pricing, key, addr) = load_data(); |
|
|
|
if (op == 0) { ;; deploy new nft |
|
int now_time = now(); |
|
slice body = read_comment(in_msg_body); |
|
(slice domain, slice signature_encoded) = split_by_semicolon(body); |
|
int len = slice_bits(domain); |
|
int price = calcprice(domain, pricing); |
|
throw_unless(204, msg_value >= price); |
|
|
|
int item_index = slice_hash(domain); |
|
|
|
slice sender_address = cs~load_msg_addr(); |
|
if (signature_needed) { |
|
slice signature = decode_asciicode(signature_encoded); |
|
throw_unless(205, verify_signature(signature, sender_address, domain, key)); |
|
} |
|
|
|
cell nft_content = begin_cell() |
|
.store_slice(sender_address) |
|
.store_ref(begin_cell().store_slice(domain).end_cell()) |
|
.end_cell(); |
|
deploy_nft_item(item_index, nft_item_code, nft_content); |
|
return (); |
|
} |
|
|
|
if (op == op::fill_up) { ;; just fill-up balance |
|
return (); |
|
} |
|
throw(0xffff); |
|
} |
|
|
|
;; Get methods |
|
|
|
(int, cell, slice) get_collection_data() method_id { |
|
var (content, nft_item_code, pricing, key, addr) = load_data(); |
|
return (-1, content, zero_address()); |
|
} |
|
|
|
slice get_nft_address_by_index(int index) method_id { |
|
var (content, nft_item_code, pricing, key, addr) = load_data(); |
|
cell state_init = calculate_nft_item_state_init(index, nft_item_code); |
|
return calculate_nft_item_address(workchain(), state_init); |
|
} |
|
|
|
cell get_nft_content(int index, cell individual_nft_content) method_id { |
|
return individual_nft_content; |
|
} |
|
|
|
(int, cell) dnsresolve(slice subdomain, int category) method_id { |
|
throw_unless(70, mod(slice_bits(subdomain), 8) == 0); |
|
|
|
int starts_with_zero_byte = subdomain.preload_int(8) == 0; |
|
|
|
if (starts_with_zero_byte & (slice_bits(subdomain) == 8)) { ;; "." requested |
|
return (8, null()); ;; resolved but no dns-records |
|
} |
|
if (starts_with_zero_byte) { |
|
subdomain~load_uint(8); |
|
} |
|
|
|
int top_subdomain_bits = get_top_domain_bits(subdomain); |
|
slice top_subdomain = subdomain~load_bits(top_subdomain_bits); |
|
int item_index = slice_hash(top_subdomain); |
|
cell result = begin_cell() |
|
.store_uint(dns_next_resolver_prefix, 16) |
|
.store_slice(get_nft_address_by_index(item_index)) |
|
.end_cell(); |
|
return (top_subdomain_bits + (starts_with_zero_byte ? 8 : 0), result); |
|
}
|
|
|