From 443321588edab37249b1cafb29c9f5f70231e395 Mon Sep 17 00:00:00 2001 From: ennucore Date: Tue, 24 Jan 2023 22:38:57 +0100 Subject: [PATCH] Initializing the nft content in the same content; working with records --- bin/api.js | 8 +++----- contracts/main.ts | 37 +++++++++++++++++++++++++------------ contracts/nft-collection.fc | 33 ++++++++++++++++++++++----------- contracts/nft-item.fc | 9 +++++++-- test/item.spec.ts | 2 +- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/bin/api.js b/bin/api.js index 939cc88..bf631c9 100644 --- a/bin/api.js +++ b/bin/api.js @@ -1,11 +1,9 @@ const main = require('../contracts/main'); const {Address, Cell, Slice} = require("ton"); const {Base64} = require('@tonconnect/protocol'); -const BN = require("bn.js"); const express = require('express') const {get_tonclient, AdnlAddress} = require("../contracts/utils"); -const {sha256} = require("ton-crypto"); const {getRecords} = require("../contracts/main"); const app = express() const port = 5171 @@ -17,7 +15,7 @@ app.use(function(err, req, res, next) { console.log("error"); res.send("error"); }); -app.get('/', (req, res) => { +app.get('/', async (req, res) => { res.send('Agorata microservice for dealing with TON') }) @@ -58,13 +56,13 @@ app.get('/get-records/:address', async (req, res) => { app.get('/set-record/site/:site', async (req, res) => { let site = new AdnlAddress(req.params.site); - let msg = main.changeRecordMsg("site", await main.AdnlRecord(site)); + let msg = await main.changeRecordMsg("site", await main.AdnlRecord(site)); res.send(JSON.stringify(Base64.encode(msg.toBoc()))); }) app.get('/set-record/wallet/:wallet', async (req, res) => { let wallet = Address.parse(req.params.wallet); - let msg = main.changeRecordMsg("wallet", await main.WalletRecord(wallet)); + let msg = await main.changeRecordMsg("wallet", await main.WalletRecord(wallet)); res.send(JSON.stringify(Base64.encode(msg.toBoc()))); }) diff --git a/contracts/main.ts b/contracts/main.ts index ca6a46d..9968be3 100644 --- a/contracts/main.ts +++ b/contracts/main.ts @@ -11,9 +11,10 @@ import { } from "./utils"; import {randomBytes} from "crypto"; import {keyPairFromSeed, KeyPair, sign, keyPairFromSecretKey, sha256} from "ton-crypto"; -import { hex as item_code } from "../build/nft-item.compiled.json"; +import {hex as item_code} from "../build/nft-item.compiled.json"; import {randomAddress} from "../test/helpers"; import {hashCell} from "ton/dist/boc/boc"; +import {Base64} from "@tonconnect/protocol"; // encode contract storage according to save_data() contract method @@ -64,6 +65,11 @@ export function collectionData(params: { .storeRef(beginCell().storeUint(params.price_multiplier, 8).storeUint(params.price_steepness, 4).endCell()) .storeUint(params.ownerKey, 256) .storeAddress(params.ownerAddress) + .storeRef( + beginCell() + .storeRef(beginCell().storeBuffer(Buffer.from(`https://api.agorata.io/data/${params.zone}/`)).endCell()) + .storeRef(beginCell().storeBuffer(Buffer.from(`.json`)).endCell()) + .endCell()) .endCell(); } @@ -75,9 +81,10 @@ export function itemDataUninit(params: { domain: String, collectionAddress: Addr .storeAddress(params.collectionAddress).endCell(); } -export function itemData(params: { +export async function itemData(params: { domain: String, collectionAddress: Address, - ownerAddress: Address }): Cell { + ownerAddress: Address +}): Promise { let domain = params.domain.split('.')[0]; let zone = params.domain.split('.').slice(1).join('.'); let index = new BN(hashCell(makeSnakeCell(Buffer.from(domain)))); @@ -85,7 +92,7 @@ export function itemData(params: { .storeUint(index, 256) .storeAddress(params.collectionAddress) .storeAddress(params.ownerAddress) - .storeRef(itemContent(domain, zone)) + .storeRef(await itemContent(domain, zone)) .storeRef(makeSnakeCell(Buffer.from(domain))) .storeUint(0, 64).endCell(); } @@ -97,9 +104,12 @@ export async function getRecords(tonclient: TonClient, address: Address) { [["tvm.Slice", "te6cckEBAQEAAwAAAgDTZ9xB"], ["num", new BN(await sha256('wallet')).toString()]])).stack[1]; if (ans_wallet[1].bytes !== undefined) { - wallet = Cell.fromBoc(Buffer.from(ans_wallet[1].bytes, 'base64'))[0].beginParse().readAddress(); + let reader = Cell.fromBoc(Buffer.from(ans_wallet[1].bytes, 'base64'))[0].beginParse() + reader.skip(16); + wallet = reader.readAddress()?.toFriendly(); } - } catch (e) {} + } catch (e) { + } let site = null; try { let ans_site = (await tonclient.callGetMethod(address, 'dnsresolve', @@ -108,16 +118,18 @@ export async function getRecords(tonclient: TonClient, address: Address) { if (ans_site[1].bytes !== undefined) { let site_data = ans_site[1].bytes; // object.data.b64; // print site_data converted from base64 - let c = Cell.fromBoc(Buffer.from(site_data, 'base64'))[0]; - site = new AdnlAddress(c.bits.buffer.subarray(2, 2 + 32)).toHex(); + let c = Cell.fromBoc(Buffer.from(site_data, 'base64'))[0].beginParse(); + c.skip(16); + site = new AdnlAddress(c.readRemainingBytes().subarray(2, 2 + 32)).toHex(); } - } catch (e) {} + } catch (e) { + } let uri = null; try { let ans_uri = (await tonclient.callGetMethod(address, 'dnsresolve', [["tvm.Slice", "te6cckEBAQEAAwAAAgDTZ9xB"], ["num", new BN(await sha256('uri')).toString()]])).stack[1]; - uri = Buffer.from(ans_uri[1].bytes, 'base64').toString(); + uri = Cell.fromBoc(Buffer.from(ans_uri[1].bytes, "base64"))[0].beginParse().readRemainingBytes().toString(); } catch (e) { console.log(e); console.log((await tonclient.callGetMethod(address, 'get_nft_data')).stack[4]); @@ -221,10 +233,11 @@ export function createItem(params: { domain: String, signature?: String }): Cell .endCell(); } -export function initializeItemMsg(params: { domain: String, ownerAddr: Address }): Cell { +export function initializeItemMsg(params: { domain: String, ownerAddr: Address, zone: String }): Cell { return beginCell() .storeAddress(params.ownerAddr) - .storeRef(makeSnakeCell(Buffer.from(params.domain))) + .storeRef(beginCell().storeBuffer(Buffer.from(params.domain)).endCell()) + .storeRef(beginCell().storeBuffer(Buffer.from(`https://api.agorata.io/data/${params.zone}/${params.domain}.json`)).endCell()) .endCell(); } diff --git a/contracts/nft-collection.fc b/contracts/nft-collection.fc index 90061c9..c163143 100644 --- a/contracts/nft-collection.fc +++ b/contracts/nft-collection.fc @@ -10,25 +10,28 @@ ;; cell pricing ;; uint256(key) owner_key ;; address owner_address +;; cell uri_scheme: prefix slice as a cell, then postfix ('.json') slice as a cell -(cell, cell, cell, int, slice) load_data() inline { +(cell, cell, cell, int, slice, cell) 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 + ds~load_msg_addr(), ;; owner address + ds~load_ref() ;; uri_scheme ); } -() save_data(cell content, cell nft_item_code, cell pricing, int owner_key, slice owner_addr) impure inline { +() save_data(cell content, cell nft_item_code, cell pricing, int owner_key, slice owner_addr, cell uri_scheme) 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) + .store_ref(uri_scheme) .end_cell()); } @@ -50,6 +53,15 @@ cell calculate_nft_item_state_init(int item_index, cell nft_item_code) { return begin_cell().store_uint(0, 2).store_dict(nft_item_code).store_dict(data).store_uint(0, 1).end_cell(); } +cell get_uri(slice domain, cell uri_scheme) { + ;; parse the prefix and the postfix out of uri_scheme + slice cs = uri_scheme.begin_parse(); + slice prefix = cs~load_ref().begin_parse(); + slice postfix = cs~load_ref().begin_parse(); + ;; create the slice with the uri: prefix + domain + postfix + return begin_cell().store_slice(prefix).store_slice(domain).store_slice(postfix).end_cell(); +} + slice calculate_nft_item_address(int wc, cell state_init) { return begin_cell() .store_uint(4, 3) @@ -75,7 +87,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { send_raw_message(msg.end_cell(), send_mode); } -() deploy_nft_item(int item_index, cell nft_item_code, cell nft_content) impure { +() deploy_nft_item(int item_index, cell nft_item_code, cell nft_payload) 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() @@ -84,7 +96,7 @@ slice calculate_nft_item_address(int wc, cell state_init) { .store_coins(0) .store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1) .store_ref(state_init) - .store_ref(nft_content); + .store_ref(nft_payload); send_raw_message(msg.end_cell(), 64); ;; carry all the remaining value of the inbound message, fee deducted from amount } @@ -107,7 +119,7 @@ int verify_signature(slice signature, slice sender_address, slice domain, int ow int op = in_msg_body~load_uint(32); - var (content, nft_item_code, pricing, key, addr) = load_data(); + var (content, nft_item_code, pricing, key, addr, uri_scheme) = load_data(); if (op == 0) { ;; deploy new nft int now_time = now(); @@ -122,14 +134,13 @@ int verify_signature(slice signature, slice sender_address, slice domain, int ow slice sender_address = cs~load_msg_addr(); if (key != 0) { slice signature = decode_asciicode(signature_encoded); - int bbb = signature.preload_uint(8); -;; throw(300 + slice_bits(signature)); 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()) + .store_ref(get_uri(domain, uri_scheme)) .end_cell(); deploy_nft_item(item_index, nft_item_code, nft_content); return (); @@ -151,12 +162,12 @@ int verify_signature(slice signature, slice sender_address, slice domain, int ow ;; Get methods (int, cell, slice) get_collection_data() method_id { - var (content, nft_item_code, pricing, key, addr) = load_data(); + var (content, nft_item_code, pricing, key, addr, uri_scheme) = 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(); + var (content, nft_item_code, pricing, key, addr, uri_scheme) = load_data(); cell state_init = calculate_nft_item_state_init(index, nft_item_code); return calculate_nft_item_address(workchain(), state_init); } @@ -166,7 +177,7 @@ cell get_nft_content(int index, cell individual_nft_content) method_id { } int get_price(slice domain) method_id { - var (content, nft_item_code, pricing, key, addr) = load_data(); + var (content, nft_item_code, pricing, key, addr, uri_scheme) = load_data(); return calcprice(domain, pricing); } diff --git a/contracts/nft-item.fc b/contracts/nft-item.fc index afd274a..280ddf8 100644 --- a/contracts/nft-item.fc +++ b/contracts/nft-item.fc @@ -5,6 +5,9 @@ int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON +;; sha256('uri') +const uri_key = 51065135818459385347574250312853146822620586594996463797054414300406918686668; + ;; ;; === Storage === ;; @@ -104,8 +107,10 @@ int min_tons_for_storage() asm "1000000000 PUSHINT"; ;; 1 TON throw_unless(405, equal_slices(collection_address, sender_address)); slice from_address = in_msg_body~load_msg_addr(); cell domain = in_msg_body~load_ref(); - - cell content = begin_cell().store_uint(0, 8).store_dict(new_dict()).end_cell(); + cell uri = in_msg_body~load_ref(); + cell content_dict = new_dict(); + content_dict~udict_set_ref(256, uri_key, uri); + cell content = begin_cell().store_uint(0, 8).store_dict(content_dict).end_cell(); store_data(index, collection_address, from_address, content, domain, now()); return (); } diff --git a/test/item.spec.ts b/test/item.spec.ts index 4036cac..fac662f 100644 --- a/test/item.spec.ts +++ b/test/item.spec.ts @@ -36,7 +36,7 @@ describe("Creating items tests", () => { let ownerAddr = randomAddress("dude"); const initializeMsg = internalMessage({ from: randomAddress("collection"), - body: main.initializeItemMsg({domain: "levcccc", ownerAddr}), + body: main.initializeItemMsg({domain: "levcccc", ownerAddr, zone: "example.ton"}), value: new BN(0), }); const res = await contract.sendInternalMessage(initializeMsg);