From dbad5528301cf5cf6337e6edf03dde7a21c833fb Mon Sep 17 00:00:00 2001 From: ennucore Date: Tue, 24 Jan 2023 16:21:44 +0100 Subject: [PATCH] Working on item's content --- bin/api.js | 14 +++++++- contracts/main.ts | 89 +++++++++++++++++++++++++++++++++++----------- contracts/utils.ts | 17 ++++++--- test/item.spec.ts | 23 ++++++++---- 4 files changed, 109 insertions(+), 34 deletions(-) diff --git a/bin/api.js b/bin/api.js index c269e3e..939cc88 100644 --- a/bin/api.js +++ b/bin/api.js @@ -4,7 +4,7 @@ const {Base64} = require('@tonconnect/protocol'); const BN = require("bn.js"); const express = require('express') -const {get_tonclient} = require("../contracts/utils"); +const {get_tonclient, AdnlAddress} = require("../contracts/utils"); const {sha256} = require("ton-crypto"); const {getRecords} = require("../contracts/main"); const app = express() @@ -56,6 +56,18 @@ 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)); + 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)); + res.send(JSON.stringify(Base64.encode(msg.toBoc()))); +}) + app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) diff --git a/contracts/main.ts b/contracts/main.ts index 141bf5a..ca6a46d 100644 --- a/contracts/main.ts +++ b/contracts/main.ts @@ -1,7 +1,14 @@ import BN from "bn.js"; import {Cell, beginCell, Address, Slice, TonClient} from "ton"; import {SmartContract} from "ton-contract-executor"; -import {AdnlAddress, encodeOffChainContent, encodeSemiChainContent, makeSnakeCell} from "./utils"; +import { + AdnlAddress, + categoryToBN, + decodeOffChainContent, + encodeOffChainContent, + encodeSemiChainContent, + makeSnakeCell +} 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"; @@ -84,24 +91,38 @@ export function itemData(params: { } export async function getRecords(tonclient: TonClient, address: Address) { - let ans_wallet = (await tonclient.callGetMethod(address, 'dnsresolve', - [["tvm.Slice", "te6cckEBAQEAAwAAAgDTZ9xB"], - ["num", new BN(await sha256('wallet')).toString()]])).stack[1]; let wallet = null; - if (ans_wallet[1].bytes !== undefined) { - wallet = Cell.fromBoc(Buffer.from(ans_wallet[1].bytes, 'base64'))[0]; - } - let ans_site = (await tonclient.callGetMethod(address, 'dnsresolve', - [["tvm.Slice", "te6cckEBAQEAAwAAAgDTZ9xB"], - ["num", new BN(await sha256('site')).toString()]])).stack[1]; + try { + let ans_wallet = (await tonclient.callGetMethod(address, 'dnsresolve', + [["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(); + } + } catch (e) {} let site = null; - 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(); + try { + let ans_site = (await tonclient.callGetMethod(address, 'dnsresolve', + [["tvm.Slice", "te6cckEBAQEAAwAAAgDTZ9xB"], + ["num", new BN(await sha256('site')).toString()]])).stack[1]; + 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(); + } + } 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(); + } catch (e) { + console.log(e); + console.log((await tonclient.callGetMethod(address, 'get_nft_data')).stack[4]); } - return {wallet, site}; + return {wallet, site, uri}; } @@ -159,6 +180,31 @@ export function TON(): number { return 1000000000; } +export async function changeRecordMsg(category: string, value: Cell | null) { + let cell = beginCell() + .storeUint(0x4eb1f0f9, 32) + .storeUint(0, 64) + .storeUint(new BN(await categoryToBN(category)), 256); + if (value) { + cell.storeRef(value); + } + return cell.endCell(); +} + +export async function AdnlRecord(site: AdnlAddress) { + return beginCell() + .storeUint(0xad01, 16) + .storeBuffer(site.bytes) + .storeUint(0, 8).endCell(); +} + +export async function WalletRecord(wallet: Address) { + return beginCell() + .storeUint(0x9fd3, 16) + .storeAddress(wallet) + .storeUint(0, 8).endCell(); +} + // message encoders for all ops (see contracts/imports/constants.fc for consts) export function transferOwnership(params: { newOwnerAddress: Address }): Cell { @@ -187,11 +233,12 @@ async function itemContent(domain: string, zone: string): Promise { } export async function setContent(params: { domain: string, zone: string }) { - return beginCell() - .storeUint(0x1a0b9d51, 32) - .storeUint(0, 64) - .storeRef(await itemContent(params.domain, params.zone)) - .endCell(); + // return beginCell() + // .storeUint(0x1a0b9d51, 32) + // .storeUint(0, 64) + // .storeRef(await itemContent(params.domain, params.zone)) + // .endCell(); + return changeRecordMsg("uri", beginCell().storeBuffer(Buffer.from(`https://api.agorata.io/data/${params.zone}/${params.domain}.json`)).endCell()); } export function loadRecords(map_cell: Cell) { diff --git a/contracts/utils.ts b/contracts/utils.ts index 0b9dfd4..e101942 100644 --- a/contracts/utils.ts +++ b/contracts/utils.ts @@ -1,5 +1,6 @@ import {beginCell, beginDict, BitString, Cell, DictBuilder, TonClient} from "ton"; import {sha256} from "ton-crypto"; +import {BN} from "bn.js"; // from https://github.com/getgems-io/nft-contracts/blob/main/packages/nft-content/nftContent.ts @@ -69,10 +70,10 @@ export async function encodeSemiChainContent(uri: string) { export function decodeOffChainContent(content: Cell) { let data = flattenSnakeCell(content) - let prefix = data[0] - if (prefix !== OFF_CHAIN_CONTENT_PREFIX) { - throw new Error(`Unknown content prefix: ${prefix.toString(16)}`) - } + // let prefix = data[0] + // if (prefix !== OFF_CHAIN_CONTENT_PREFIX) { + // throw new Error(`Unknown content prefix: ${prefix.toString(16)}`) + // } return data.slice(1).toString() } @@ -164,4 +165,10 @@ export class AdnlAddress { } return hex; } -} \ No newline at end of file +} + +export async function categoryToBN(category: string) { + if (!category) return new BN(0); // all categories + const categoryHash = await sha256(category); + return new BN(categoryHash); +} diff --git a/test/item.spec.ts b/test/item.spec.ts index a64281c..4036cac 100644 --- a/test/item.spec.ts +++ b/test/item.spec.ts @@ -4,15 +4,16 @@ import BN from "bn.js"; chai.use(chaiBN(BN)); -import {Address, Builder, Cell, contractAddress, Slice} from "ton"; +import {Address, beginCell, Builder, Cell, contractAddress, parseDict, parseDictBitString, Slice} from "ton"; import {runContract, SmartContract} from "ton-contract-executor"; import * as main from "../contracts/main"; import {internalMessage, randomAddress} from "./helpers"; import {hex as item_code} from "../build/nft-item.compiled.json"; import {makeSnakeCell} from "../contracts/utils"; -import {keyPairFromSeed, KeyPair, sign, keyPairFromSecretKey} from "ton-crypto"; +import {keyPairFromSeed, KeyPair, sign, keyPairFromSecretKey, sha256} from "ton-crypto"; import {signBuy} from "../contracts/main"; +import {Base64} from "@tonconnect/protocol"; let data = main.itemDataUninit({domain: "test", collectionAddress: randomAddress("collection")}); @@ -35,7 +36,7 @@ describe("Creating items tests", () => { let ownerAddr = randomAddress("dude"); const initializeMsg = internalMessage({ from: randomAddress("collection"), - body: main.initializeItemMsg({domain: "test", ownerAddr}), + body: main.initializeItemMsg({domain: "levcccc", ownerAddr}), value: new BN(0), }); const res = await contract.sendInternalMessage(initializeMsg); @@ -46,16 +47,24 @@ describe("Creating items tests", () => { expect(res.exit_code).to.equal(0); const setDataMsg = internalMessage({ from: ownerAddr, - body: await main.setContent({domain: "test", zone: "example.ton"}), + body: await main.setContent({domain: "levcccc", zone: "example.ton"}), value: new BN(0), }) const res2 = await contract.sendInternalMessage(setDataMsg); expect(res2.type).to.equal("success"); expect(res2.exit_code).to.equal(0); let nft_data = await contract.invokeGetMethod("get_nft_data", []); - console.log(nft_data.result); + console.log('res4', nft_data.result[4]); // @ts-ignore - let content = (nft_data.result[4] as Slice); - + console.log(Base64.encode((nft_data.result[4] as Cell).toBoc())) + // @ts-ignore + // let content = (nft_data.result[4] as Cell).beginParse(); + // let a = parseDict(content, 256, (s) => s); + // console.log(a); + let resolved = (await contract.invokeGetMethod("dnsresolve", [ + {type: "cell_slice", value: "te6cckEBAQEAAwAAAgDTZ9xB"}, + {type: "int", value: new BN(await sha256('uri')).toString()} + ])); + expect(resolved.type).to.equal("success"); }); });