Browse Source

Modified collection & item

dev/signature-instant-buy
Lev 2 years ago
parent
commit
22a8a1c4e5
  1. 3
      build/_deploy.ts
  2. 0
      build/main._dep.ts
  3. 34
      build/nft-collection.deploy.ts
  4. 2
      contracts/imports/op-codes.fc
  5. 7
      contracts/main.fc
  6. 17
      contracts/main.ts
  7. 55
      contracts/nft-collection.fc
  8. 147
      contracts/nft-item.fc
  9. 76
      package-lock.json
  10. 2
      package.json
  11. 44
      test/creation.spec.ts

3
build/_deploy.ts

@ -76,13 +76,16 @@ async function main() {
console.log(` - ERROR: '${rootContract}' does not have 'initData()' function`); console.log(` - ERROR: '${rootContract}' does not have 'initData()' function`);
process.exit(1); process.exit(1);
} }
console.log(1);
const initDataCell = deployInitScript.initData() as Cell; const initDataCell = deployInitScript.initData() as Cell;
console.log(2);
// prepare the init message // prepare the init message
if (typeof deployInitScript.initMessage !== "function") { if (typeof deployInitScript.initMessage !== "function") {
console.log(` - ERROR: '${rootContract}' does not have 'initMessage()' function`); console.log(` - ERROR: '${rootContract}' does not have 'initMessage()' function`);
process.exit(1); process.exit(1);
} }
console.log(1);
const initMessageCell = deployInitScript.initMessage() as Cell | null; const initMessageCell = deployInitScript.initMessage() as Cell | null;
// prepare the init code cell // prepare the init code cell

0
build/main.deploy.ts → build/main._dep.ts

34
build/nft-collection.deploy.ts

@ -0,0 +1,34 @@
import * as main from "../contracts/main";
import { Address, toNano, TupleSlice, WalletContract } from "ton";
// import { sendInternalMessageWithWallet } from "../test/helpers";
import { hex } from "../build/nft-item.compiled.json";
import { Builder, Cell, Slice } from "ton";
// return the init Cell of the contract storage (according to load_data() contract method)
export function initData() {
return main.collectionData({
ownerAddress: Address.parseFriendly("kQBw4_jZTQVbOSDbUjAMibTHWbstrCqjOnzvUTCphGpTFDrK").address,
code: Cell.fromBoc(hex)[0],
ownerKey: 0 // 63181357919630091755807889549433422416741950993093777020964723182484811889834
});
}
// return the op that should be sent to the contract on deployment, can be "null" to send an empty message
export function initMessage() {
return null;
}
// optional end-to-end sanity test for the actual on-chain contract to see it is actually working on-chain
// export async function postDeployTest(walletContract: WalletContract, secretKey: Buffer, contractAddress: Address) {
// const call = await walletContract.client.callGetMethod(contractAddress, "counter");
// const counter = new TupleSlice(call.stack).readBigNumber();
// console.log(` # Getter 'counter' = ${counter.toString()}`);
//
// const message = main.increment();
// await sendInternalMessageWithWallet({ walletContract, secretKey, to: contractAddress, value: toNano(0.02), body: message });
// console.log(` # Sent 'increment' op message`);
//
// const call2 = await walletContract.client.callGetMethod(contractAddress, "counter");
// const counter2 = new TupleSlice(call2.stack).readBigNumber();
// console.log(` # Getter 'counter' = ${counter2.toString()}`);
// }

2
contracts/imports/op-codes.fc

@ -17,7 +17,7 @@ int op::editorship_assigned() asm "0x511a4463 PUSHINT";
;; Collection ;; Collection
int op::new_nft() asm "0x1a039a51 PUSHINT"; int op::new_nft() asm "0x1a039a51 PUSHINT";
int op::instant_buy_new_nft() asm "16c7d435 PUSHINT"; int op::instant_buy_new_nft() asm "0x16c7d435 PUSHINT";
;; DNS ;; DNS
const int op::fill_up = 0x370fec51; const int op::fill_up = 0x370fec51;

7
contracts/main.fc

@ -9,6 +9,7 @@
int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON
const sign_key = 0;
;; =============== storage ============================= ;; =============== storage =============================
;; ;;
@ -328,14 +329,14 @@ cell pack_nft_item_state(cell nft_item_code, cell data) impure {
throw_unless(411, slice_bits(new_domain) > 0); throw_unless(411, slice_bits(new_domain) > 0);
throw_unless(412, equal_slices(receiver_addr, sender_address)); ;; TODO: Unsure here throw_unless(412, equal_slices(receiver_addr, sender_address)); ;; TODO: Unsure here
throw_unless(413, equal_slices(issued_collection_addr, my_address())); throw_unless(413, equal_slices(issued_collection_addr, my_address()));
int success = check_data_signature(option_data.begin_parse(), signature.begin_parse(), owner_address); int success = check_signature(slice_hash(option_data.begin_parse()), signature.begin_parse(), sign_key);
throw_unless(413, success); throw_unless(413, success);
throw_unless(414, msg_value > amount); throw_unless(414, msg_value > amount);
amount_to_send = msg_value - amount; ;; TODO: Handle this later, reroute coins var amount_to_send = msg_value - amount; ;; TODO: Handle this later, reroute coins
int new_item_index = slice_hash(new_domain); int new_item_index = slice_hash(new_domain);
deploy_bought_item(item_index, cell item_code, slice receiver_addr, slice new_domain); ;; deploy_bought_item(item_index, cell item_code, slice receiver_addr, slice new_domain);
return (); return ();
;; init_state = pack_state(... add domain here ...) ;; init_state = pack_state(... add domain here ...)

17
contracts/main.ts

@ -26,6 +26,16 @@ export function data(params: { ownerAddress: Address; collectionAddress: Address
.storeUint(0, 64).endCell(); .storeUint(0, 64).endCell();
} }
export function collectionData(params: { code: Cell, ownerAddress: Address, ownerKey: number }): Cell {
return beginCell()
.storeRef(encodeOffChainContent("https://agorata.io/collection.json"))
.storeRef(params.code)
.storeRef(beginCell().endCell())
.storeUint(params.ownerKey, 256)
.storeAddress(params.ownerAddress)
.endCell();
}
export function auctionWithWinner(winnerAddress: Address) { export function auctionWithWinner(winnerAddress: Address) {
return beginCell().storeAddress(winnerAddress).storeCoins(0).storeUint(0, 64) return beginCell().storeAddress(winnerAddress).storeCoins(0).storeUint(0, 64)
} }
@ -42,6 +52,13 @@ export function transferOwnership(params: { newOwnerAddress: Address }): Cell {
return beginCell().storeUint(0x5fcc3d14, 32).storeUint(0, 64).storeAddress(params.newOwnerAddress).storeAddress(null).storeInt(0, 1).storeCoins(1 * TON()).endCell(); return beginCell().storeUint(0x5fcc3d14, 32).storeUint(0, 64).storeAddress(params.newOwnerAddress).storeAddress(null).storeInt(0, 1).storeCoins(1 * TON()).endCell();
} }
export function createItem(params: { domain: String }): Cell {
return beginCell()
.storeUint(0, 32)
.storeRef(makeSnakeCell(Buffer.from(params.domain)))
.endCell();
}
export function currentState(contract: SmartContract) { export function currentState(contract: SmartContract) {
let reader = contract.dataCell.beginParse(); let reader = contract.dataCell.beginParse();
return { return {

55
contracts/nft-collection.fc

@ -4,25 +4,43 @@
#include "imports/params.fc"; #include "imports/params.fc";
;; storage scheme ;; storage scheme
;; storage#_ collection_content:^Cell ;; cell collection_content
;; nft_item_code:^Cell ;; cell nft_item_code
;; = Storage; ;; cell pricing
;; uint256(key) owner_key
;; address owner_address
(cell, cell) load_data() inline { (cell, cell, cell, int, slice) load_data() inline {
var ds = get_data().begin_parse(); var ds = get_data().begin_parse();
return ( return (
ds~load_ref(), ;; content ds~load_ref(), ;; content
ds~load_ref() ;; nft_item_code 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) impure inline { () save_data(cell content, cell nft_item_code, cell pricing, int owner_key, slice owner_addr) impure inline {
set_data(begin_cell() set_data(begin_cell()
.store_ref(content) .store_ref(content)
.store_ref(nft_item_code) .store_ref(nft_item_code)
.store_ref(pricing)
.store_uint(owner_key, 256)
.store_slice(owner_addr)
.end_cell()); .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 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(); 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(); return begin_cell().store_uint(0, 2).store_dict(nft_item_code).store_dict(data).store_uint(0, 1).end_cell();
@ -60,34 +78,21 @@ slice calculate_nft_item_address(int wc, cell state_init) {
if (flags & 1) { ;; ignore all bounced messages if (flags & 1) { ;; ignore all bounced messages
return (); return ();
} }
slice sender_address = cs~load_msg_addr();
int op = in_msg_body~load_uint(32); int op = in_msg_body~load_uint(32);
var (content, nft_item_code) = load_data(); var (content, nft_item_code, pricing, key, addr) = load_data();
if (op == 0) { ;; deploy new nft if (op == 0) { ;; deploy new nft
int now_time = now(); int now_time = now();
throw_unless(199, now_time > auction_start_time); ;; start of auction
slice domain = read_domain_from_comment(in_msg_body); slice domain = read_domain_from_comment(in_msg_body);
int len = slice_bits(domain); int len = slice_bits(domain);
throw_unless(200, len > 3 * 8); ;; minimum 4 characters int price = calcprice(domain, pricing);
throw_unless(201, len <= 126 * 8); ;; maxmimum 126 characters throw_unless(204, msg_value >= price);
throw_unless(202, mod(len, 8) == 0);
throw_unless(203, check_domain_string(domain));
int min_price = get_min_price(len, now_time);
throw_unless(204, msg_value >= min_price);
int item_index = slice_hash(domain); int item_index = slice_hash(domain);
cell config_cell = config_param(dns_config_id); slice sender_address = cs~load_msg_addr();
if (~ cell_null?(config_cell)) {
slice config_cs = config_cell.begin_parse();
cell config = config_cs~load_dict();
(slice config_value, int found) = config.udict_get?(256, item_index);
throw_if(205, found);
}
cell nft_content = begin_cell() cell nft_content = begin_cell()
.store_slice(sender_address) .store_slice(sender_address)
.store_ref(begin_cell().store_slice(domain).end_cell()) .store_ref(begin_cell().store_slice(domain).end_cell())
@ -105,12 +110,12 @@ slice calculate_nft_item_address(int wc, cell state_init) {
;; Get methods ;; Get methods
(int, cell, slice) get_collection_data() method_id { (int, cell, slice) get_collection_data() method_id {
var (content, nft_item_code) = load_data(); var (content, nft_item_code, pricing, key, addr) = load_data();
return (-1, content, zero_address()); return (-1, content, zero_address());
} }
slice get_nft_address_by_index(int index) method_id { slice get_nft_address_by_index(int index) method_id {
var (content, nft_item_code) = load_data(); var (content, nft_item_code, pricing, key, addr) = load_data();
cell state_init = calculate_nft_item_state_init(index, nft_item_code); cell state_init = calculate_nft_item_state_init(index, nft_item_code);
return calculate_nft_item_address(workchain(), state_init); return calculate_nft_item_address(workchain(), state_init);
} }

147
contracts/nft-item.fc

@ -5,52 +5,27 @@
int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON
const auction_start_duration = 604800; ;; 1 week = 60 * 60 * 24 * 7; in testnet 5 min
const auction_end_duration = 3600; ;; 1 hour = 60 * 60; in testnet 1 min
const auction_prolongation = 3600; ;; 1 hour = 60 * 60; in testnet 1 min
;; MsgAddressInt max_bid_address
;; Coins max_bid_amount
;; int auction_end_time
(slice, int, int) unpack_auction(cell auction) {
if (cell_null?(auction)) {
return (null(), 0, 0);
} else {
slice ds = auction.begin_parse();
return (ds~load_msg_addr(), ds~load_coins(), ds~load_uint(64));
}
}
cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_time) {
return begin_cell()
.store_slice(max_bid_address)
.store_coins(max_bid_amount)
.store_uint(auction_end_time, 64)
.end_cell();
}
;; ;;
;; Storage ;; === Storage ===
;; ;;
;; uint256 index ;; uint256 index
;; MsgAddressInt collection_address ;; MsgAddressInt collection_address
;; MsgAddressInt owner_address ;; MsgAddressInt owner_address
;; cell content ;; cell content
;; cell domain - e.g contains "alice" (without ending \0) for "alice.ton" domain ;; cell domain - e.g contains "alice" (without ending \0) for "alice.ton" domain
;; cell auction - auction info
;; int last_fill_up_time ;; int last_fill_up_time
(int, int, slice, slice, cell, cell, cell, int) load_data() { (int, int, slice, slice, cell, cell, int) load_data() {
slice ds = get_data().begin_parse(); slice ds = get_data().begin_parse();
var (index, collection_address) = (ds~load_uint(256), ds~load_msg_addr()); var (index, collection_address) = (ds~load_uint(256), ds~load_msg_addr());
if (ds.slice_bits() > 0) { if (ds.slice_bits() > 0) {
return (-1, index, collection_address, ds~load_msg_addr(), ds~load_ref(), ds~load_ref(), ds~load_dict(), ds~load_uint(64)); return (-1, index, collection_address, ds~load_msg_addr(), ds~load_ref(), ds~load_ref(), ds~load_uint(64));
} else { } else {
return (0, index, collection_address, null(), null(), null(), null(), 0); ;; nft not initialized yet return (0, index, collection_address, null(), null(), null(), 0); ;; nft not initialized yet
} }
} }
() store_data(int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) impure { () store_data(int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) impure {
set_data( set_data(
begin_cell() begin_cell()
.store_uint(index, 256) .store_uint(index, 256)
@ -58,7 +33,6 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
.store_slice(owner_address) .store_slice(owner_address)
.store_ref(content) .store_ref(content)
.store_ref(domain) .store_ref(domain)
.store_dict(auction)
.store_uint(last_fill_up_time, 64) .store_uint(last_fill_up_time, 64)
.end_cell() .end_cell()
); );
@ -80,7 +54,7 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
send_raw_message(msg.end_cell(), send_mode); 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, cell domain, cell auction) impure inline { () 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, cell domain) impure inline {
slice new_owner_address = in_msg_body~load_msg_addr(); slice new_owner_address = in_msg_body~load_msg_addr();
force_chain(new_owner_address); force_chain(new_owner_address);
slice response_destination = in_msg_body~load_msg_addr(); slice response_destination = in_msg_body~load_msg_addr();
@ -106,7 +80,7 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
send_msg(response_destination, rest_amount, op::excesses(), query_id, null(), 1); ;; paying fees, revert on errors 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, domain, auction, now()); store_data(index, collection_address, new_owner_address, content, domain, now());
} }
() recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure { () recv_internal(int msg_value, cell in_msg_full, slice in_msg_body) impure {
@ -125,23 +99,14 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
cs~load_coins(); ;; skip ihr_fee cs~load_coins(); ;; skip ihr_fee
int fwd_fee = cs~load_coins(); ;; we use message fwd_fee for estimation of forward_payload costs int fwd_fee = cs~load_coins(); ;; we use message fwd_fee for estimation of forward_payload costs
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) = load_data();
if (~ init?) { if (~ init?) {
throw_unless(405, equal_slices(collection_address, sender_address)); throw_unless(405, equal_slices(collection_address, sender_address));
slice from_address = in_msg_body~load_msg_addr(); slice from_address = in_msg_body~load_msg_addr();
cell domain = in_msg_body~load_ref(); cell domain = in_msg_body~load_ref();
cell content = begin_cell().store_uint(0, 8).store_dict(new_dict()).end_cell(); cell content = begin_cell().store_uint(0, 8).store_dict(new_dict()).end_cell();
store_data(index, collection_address, from_address, content, domain, now());
int seconds = now() - auction_start_time;
int months = seconds / one_month;
if (months > 12) {
months = 12;
}
int duration = auction_start_duration - (auction_start_duration - auction_end_duration) * months / 12;
int auction_end_time = now() + duration;
store_data(index, collection_address, zero_address(), content, domain, pack_auction(from_address, msg_value, auction_end_time), now());
return (); return ();
} }
@ -153,55 +118,53 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
int op = in_msg_body.slice_empty?() ? 0 : in_msg_body~load_uint(32); int op = in_msg_body.slice_empty?() ? 0 : in_msg_body~load_uint(32);
(slice max_bid_address, int max_bid_amount, int auction_end_time) = unpack_auction(auction);
int auction_complete = now() > auction_end_time;
if (op == 0) { if (op == 0) { ;; todo
if (auction_complete) { ;; if (auction_complete) {
throw_unless(406, equal_slices(sender_address, owner_address)); ;; only owner can fill-up balance, prevent coins lost right after the auction ;; throw_unless(406, equal_slices(sender_address, owner_address)); ;; only owner can fill-up balance, prevent coins lost right after the auction
;; if owner send bid right after auction he can restore it by transfer resonse message ;; ;; if owner send bid right after auction he can restore it by transfer resonse message
store_data(index, collection_address, owner_address, content, domain, auction, now()); store_data(index, collection_address, owner_address, content, domain, now());
} else { ;; } else {
throw_unless(407, msg_value >= muldiv(max_bid_amount, 105, 100)); ;; 5% greater then previous bid ;; throw_unless(407, msg_value >= muldiv(max_bid_amount, 105, 100)); ;; 5% greater then previous bid
int amount_to_send = (max_bid_amount > my_balance - min_tons_for_storage()) ? (my_balance - min_tons_for_storage()) : max_bid_amount; ;; int amount_to_send = (max_bid_amount > my_balance - min_tons_for_storage()) ? (my_balance - min_tons_for_storage()) : max_bid_amount;
if (amount_to_send > 0) { ;; if (amount_to_send > 0) {
send_msg(max_bid_address, amount_to_send, op::outbid_notification, cur_lt(), null(), 1); ;; pay transfer fees separately ;; send_msg(max_bid_address, amount_to_send, op::outbid_notification, cur_lt(), null(), 1); ;; pay transfer fees separately
} ;; }
max_bid_amount = msg_value; ;; max_bid_amount = msg_value;
max_bid_address = sender_address; ;; max_bid_address = sender_address;
int delta_time = auction_prolongation - (auction_end_time - now()); ;; int delta_time = auction_prolongation - (auction_end_time - now());
if (delta_time > 0) { ;; if (delta_time > 0) {
auction_end_time += delta_time; ;; auction_end_time += delta_time;
} ;; }
store_data(index, collection_address, owner_address, content, domain, pack_auction(max_bid_address, max_bid_amount, auction_end_time), now()); ;; store_data(index, collection_address, owner_address, content, domain, now());
} ;; }
return (); return ();
} }
int query_id = in_msg_body~load_uint(64); int query_id = in_msg_body~load_uint(64);
if ((auction_complete) & (~ cell_null?(auction))) { ;; take domain after auction ;; if ((auction_complete) & (~ cell_null?(auction))) { ;; take domain after auction ;; todo
int balance_without_msg = my_balance - msg_value; ;; int balance_without_msg = my_balance - msg_value;
int amount_to_send = (max_bid_amount > balance_without_msg - min_tons_for_storage()) ? (balance_without_msg - min_tons_for_storage()) : max_bid_amount; ;; int amount_to_send = (max_bid_amount > balance_without_msg - min_tons_for_storage()) ? (balance_without_msg - min_tons_for_storage()) : max_bid_amount;
if (amount_to_send > 0) { ;; if (amount_to_send > 0) {
send_msg(collection_address, amount_to_send, op::fill_up, query_id, null(), 2); ;; ignore errors ;; send_msg(collection_address, amount_to_send, op::fill_up, query_id, null(), 2); ;; ignore errors
my_balance -= amount_to_send; ;; my_balance -= amount_to_send;
} ;; }
owner_address = max_bid_address; ;; owner_address = max_bid_address;
auction = null(); ;; auction = null();
store_data(index, collection_address, owner_address, content, domain, auction, last_fill_up_time); ;; store_data(index, collection_address, owner_address, content, domain, last_fill_up_time);
} ;; }
if (op == op::transfer()) { if (op == op::transfer()) {
throw_unless(401, equal_slices(sender_address, owner_address)); throw_unless(401, equal_slices(sender_address, owner_address));
transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, in_msg_body, fwd_fee, domain, auction); transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, in_msg_body, fwd_fee, domain);
return (); return ();
} }
if (op == op::edit_content()) { ;; owner can change content and dns records if (op == op::edit_content()) { ;; owner can change content and dns records
throw_unless(410, equal_slices(sender_address, owner_address)); throw_unless(410, equal_slices(sender_address, owner_address));
store_data(index, collection_address, owner_address, in_msg_body~load_ref(), domain, auction, now()); store_data(index, collection_address, owner_address, in_msg_body~load_ref(), domain, now());
return (); return ();
} }
if (op == op::change_dns_record) { ;; change dns record if (op == op::change_dns_record) { ;; change dns record
@ -223,11 +186,10 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
content = begin_cell().store_uint(0, 8).store_dict(keyvalue_map).end_cell(); content = begin_cell().store_uint(0, 8).store_dict(keyvalue_map).end_cell();
store_data(index, collection_address, owner_address, content, domain, auction, now()); store_data(index, collection_address, owner_address, content, domain, now());
return (); return ();
} }
if (op == op::process_governance_decision) { ;; governance if (op == op::process_governance_decision) { ;; governance
throw_unless(413, cell_null?(auction));
slice cs = config_param(dns_config_id).begin_parse(); slice cs = config_param(dns_config_id).begin_parse();
cell config = cs~load_dict(); cell config = cs~load_dict();
(slice config_value, int found) = config.udict_get?(256, index); (slice config_value, int found) = config.udict_get?(256, index);
@ -235,7 +197,7 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
int config_op = config_value~load_uint(8); int config_op = config_value~load_uint(8);
throw_unless(416, (config_op == 0) | (config_op == 1)); throw_unless(416, (config_op == 0) | (config_op == 1));
if (config_op == 0) { ;; transfer if (config_op == 0) { ;; transfer
transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, config_value, fwd_fee, domain, auction); transfer_ownership(my_balance, index, collection_address, owner_address, content, sender_address, query_id, config_value, fwd_fee, domain);
} }
if (config_op == 1) { ;; destroy if (config_op == 1) { ;; destroy
send_msg(collection_address, 0, op::fill_up, query_id, null(), 128 + 32); ;; carry all the remaining balance + destroy send_msg(collection_address, 0, op::fill_up, query_id, null(), 128 + 32); ;; carry all the remaining balance + destroy
@ -243,7 +205,7 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
return (); return ();
} }
if (op == op::dns_balance_release) { ;; release domain if (op == op::dns_balance_release) { ;; release domain
throw_unless(414, (now() - last_fill_up_time > one_year) & (cell_null?(auction))); throw_unless(414, (now() - last_fill_up_time > one_year));
int min_price = get_min_price(domain.begin_parse().slice_bits(), now()); int min_price = get_min_price(domain.begin_parse().slice_bits(), now());
throw_unless(407, msg_value >= min_price); throw_unless(407, msg_value >= min_price);
int balance_without_msg = my_balance - msg_value; int balance_without_msg = my_balance - msg_value;
@ -251,12 +213,8 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
if (amount_to_send > 0) { if (amount_to_send > 0) {
send_msg(owner_address, amount_to_send, op::dns_balance_release, query_id, null(), 2); ;; ignore errors send_msg(owner_address, amount_to_send, op::dns_balance_release, query_id, null(), 2); ;; ignore errors
} }
max_bid_amount = msg_value;
max_bid_address = sender_address;
auction_end_time = now() + auction_start_duration; ;; always 1 week
owner_address = zero_address(); owner_address = zero_address();
auction = pack_auction(max_bid_address, max_bid_amount, auction_end_time); store_data(index, collection_address, owner_address, content, domain, now());
store_data(index, collection_address, owner_address, content, domain, auction, now());
return (); return ();
} }
if (op == op::get_static_data()) { if (op == op::get_static_data()) {
@ -271,27 +229,22 @@ cell pack_auction(slice max_bid_address, int max_bid_amount, int auction_end_tim
;; ;;
(int, int, slice, slice, cell) get_nft_data() method_id { (int, int, slice, slice, cell) get_nft_data() method_id {
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) = load_data();
return (init?, index, collection_address, owner_address, content); return (init?, index, collection_address, owner_address, content);
} }
slice get_editor() method_id { slice get_editor() method_id {
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) = load_data();
return owner_address; return owner_address;
} }
slice get_domain() method_id { slice get_domain() method_id {
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) = load_data();
return domain.begin_parse(); return domain.begin_parse();
} }
(slice, int, int) get_auction_info() method_id {
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data();
return unpack_auction(auction);
}
int get_last_fill_up_time() method_id { int get_last_fill_up_time() method_id {
(int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell domain, int last_fill_up_time) = load_data();
return last_fill_up_time; return last_fill_up_time;
} }
@ -300,7 +253,7 @@ int get_last_fill_up_time() method_id {
throw_unless(70, mod(subdomain_bits, 8) == 0); throw_unless(70, mod(subdomain_bits, 8) == 0);
(int init?, int index, slice collection_address, slice owner_address, cell content, cell my_domain_cell, cell auction, int last_fill_up_time) = load_data(); (int init?, int index, slice collection_address, slice owner_address, cell content, cell my_domain_cell, int last_fill_up_time) = load_data();
slice cs = content.begin_parse(); slice cs = content.begin_parse();
throw_unless(412, cs~load_uint(8) == 0); ;; data onchain tag throw_unless(412, cs~load_uint(8) == 0); ;; data onchain tag

76
package-lock.json generated

@ -26,7 +26,7 @@
"mocha": "^9.1.3", "mocha": "^9.1.3",
"prando": "^6.0.1", "prando": "^6.0.1",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"ton": "9.9.0", "ton": "^12.1.3",
"ton-contract-executor": "^0.4.8", "ton-contract-executor": "^0.4.8",
"ton-crypto": "^3.1.0", "ton-crypto": "^3.1.0",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",
@ -1715,9 +1715,9 @@
} }
}, },
"node_modules/ton": { "node_modules/ton": {
"version": "9.9.0", "version": "12.3.3",
"resolved": "https://registry.npmjs.org/ton/-/ton-9.9.0.tgz", "resolved": "https://registry.npmjs.org/ton/-/ton-12.3.3.tgz",
"integrity": "sha512-6t+/5b/6DbQH58ywJoc96CN1txcxXjZfYXk/vDeJClqfFR5Z9QikfoPGjLPHTkpLo8jALGPrcKnZDYIwU6biew==", "integrity": "sha512-5vwy7bwuUgOY7Injqi5Ei+Opsr9AjcS4qHzzdiUdt51O2W9oz4LE/GREXuv7Uvxsxev4cWXx0sic0ohfR8Yu4g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"axios": "^0.25.0", "axios": "^0.25.0",
@ -1765,6 +1765,36 @@
"ton-compiler": "^0.9.0" "ton-compiler": "^0.9.0"
} }
}, },
"node_modules/ton-contract-executor/node_modules/ton": {
"version": "9.9.0",
"resolved": "https://registry.npmjs.org/ton/-/ton-9.9.0.tgz",
"integrity": "sha512-6t+/5b/6DbQH58ywJoc96CN1txcxXjZfYXk/vDeJClqfFR5Z9QikfoPGjLPHTkpLo8jALGPrcKnZDYIwU6biew==",
"dev": true,
"dependencies": {
"axios": "^0.25.0",
"bn.js": "5.2.0",
"dataloader": "^2.0.0",
"ethjs-unit": "0.1.6",
"fp-ts": "^2.11.1",
"io-ts": "^2.2.16",
"io-ts-reporters": "^2.0.0",
"symbol.inspect": "1.0.1",
"teslabot": "^1.3.0",
"ton-crypto": "2.1.0",
"tweetnacl": "1.0.3"
}
},
"node_modules/ton-contract-executor/node_modules/ton-crypto": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ton-crypto/-/ton-crypto-2.1.0.tgz",
"integrity": "sha512-PZnmCOShfgq9tCRM8E7hG8nCkpkOyZvDLPXmZN92ZEBrfTT0NKKf0imndkxG5DkgWMjc6IKfgpnEaJDH9qN6ZQ==",
"dev": true,
"dependencies": {
"jssha": "3.2.0",
"ton-crypto-primitives": "2.0.0",
"tweetnacl": "1.0.3"
}
},
"node_modules/ton-crypto": { "node_modules/ton-crypto": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/ton-crypto/-/ton-crypto-3.1.0.tgz", "resolved": "https://registry.npmjs.org/ton-crypto/-/ton-crypto-3.1.0.tgz",
@ -3161,9 +3191,9 @@
} }
}, },
"ton": { "ton": {
"version": "9.9.0", "version": "12.3.3",
"resolved": "https://registry.npmjs.org/ton/-/ton-9.9.0.tgz", "resolved": "https://registry.npmjs.org/ton/-/ton-12.3.3.tgz",
"integrity": "sha512-6t+/5b/6DbQH58ywJoc96CN1txcxXjZfYXk/vDeJClqfFR5Z9QikfoPGjLPHTkpLo8jALGPrcKnZDYIwU6biew==", "integrity": "sha512-5vwy7bwuUgOY7Injqi5Ei+Opsr9AjcS4qHzzdiUdt51O2W9oz4LE/GREXuv7Uvxsxev4cWXx0sic0ohfR8Yu4g==",
"dev": true, "dev": true,
"requires": { "requires": {
"axios": "^0.25.0", "axios": "^0.25.0",
@ -3219,6 +3249,38 @@
"bn.js": "^5.2.0", "bn.js": "^5.2.0",
"ton": "^9.6.3", "ton": "^9.6.3",
"ton-compiler": "^0.9.0" "ton-compiler": "^0.9.0"
},
"dependencies": {
"ton": {
"version": "9.9.0",
"resolved": "https://registry.npmjs.org/ton/-/ton-9.9.0.tgz",
"integrity": "sha512-6t+/5b/6DbQH58ywJoc96CN1txcxXjZfYXk/vDeJClqfFR5Z9QikfoPGjLPHTkpLo8jALGPrcKnZDYIwU6biew==",
"dev": true,
"requires": {
"axios": "^0.25.0",
"bn.js": "5.2.0",
"dataloader": "^2.0.0",
"ethjs-unit": "0.1.6",
"fp-ts": "^2.11.1",
"io-ts": "^2.2.16",
"io-ts-reporters": "^2.0.0",
"symbol.inspect": "1.0.1",
"teslabot": "^1.3.0",
"ton-crypto": "2.1.0",
"tweetnacl": "1.0.3"
}
},
"ton-crypto": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ton-crypto/-/ton-crypto-2.1.0.tgz",
"integrity": "sha512-PZnmCOShfgq9tCRM8E7hG8nCkpkOyZvDLPXmZN92ZEBrfTT0NKKf0imndkxG5DkgWMjc6IKfgpnEaJDH9qN6ZQ==",
"dev": true,
"requires": {
"jssha": "3.2.0",
"ton-crypto-primitives": "2.0.0",
"tweetnacl": "1.0.3"
}
}
} }
}, },
"ton-crypto": { "ton-crypto": {

2
package.json

@ -26,7 +26,7 @@
"mocha": "^9.1.3", "mocha": "^9.1.3",
"prando": "^6.0.1", "prando": "^6.0.1",
"prettier": "^2.6.2", "prettier": "^2.6.2",
"ton": "9.9.0", "ton": "^12.1.3",
"ton-contract-executor": "^0.4.8", "ton-contract-executor": "^0.4.8",
"ton-crypto": "^3.1.0", "ton-crypto": "^3.1.0",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",

44
test/creation.spec.ts

@ -0,0 +1,44 @@
import chai, { assert, expect } from "chai";
import chaiBN from "chai-bn";
import BN from "bn.js";
chai.use(chaiBN(BN));
import { Builder, Cell, Slice } from "ton";
import { SmartContract } from "ton-contract-executor";
import * as main from "../contracts/main";
import { internalMessage, randomAddress } from "./helpers";
import { hex } from "../build/nft-collection.compiled.json";
describe("Creating items tests", () => {
let contract: SmartContract;
let debug: boolean = false;
beforeEach(async () => {
contract = await SmartContract.fromCell(
Cell.fromBoc(hex)[0],
main.collectionData({
ownerAddress: randomAddress("owner"),
code: Cell.fromBoc(hex)[0],
ownerKey: 0,
}),
{ debug: debug }
);
});
it("allows to buy an item", async () => {
main.setContractBalance(contract, 10 * main.TON());
let ownerAddr = randomAddress("owner");
const sendToSelfMessage = internalMessage({
from: ownerAddr,
body: main.createItem({ domain: "test" }),
value: new BN(10 * main.TON()),
});
const res = await contract.sendInternalMessage(sendToSelfMessage);
console.log(res);
expect(res.type).to.equal("success");
expect(res.exit_code).to.equal(0);
});
});
Loading…
Cancel
Save