Skip to content

Commit

Permalink
Merge pull request #76 from hollow-leaf/feat/frontend_arch
Browse files Browse the repository at this point in the history
feat: frontend_arch
  • Loading branch information
LinXJ1204 authored Sep 15, 2023
2 parents d50dafc + b79a21d commit a184fb4
Show file tree
Hide file tree
Showing 32 changed files with 1,474 additions and 298 deletions.
450 changes: 450 additions & 0 deletions apps/backend/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"fs": "^0.0.1-security",
"ipfs-unixfs": "^11.0.1",
"multiformats": "^12.0.1",
"path": "^0.12.7"
"path": "^0.12.7",
"ton": "^13.6.1",
"ton-crypto": "^3.2.0"
}
}
40 changes: 39 additions & 1 deletion apps/backend/server.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { createRequire } from 'module';
import { add_asset } from './src/co2storage/add_asset.js';
import { sign_cid } from './src/co2storage/sign_cid.js';
import { search_asset, search_proven } from './src/co2storage/search.js';
import { search_asset, search_proven, search_assets } from './src/co2storage/search.js';
import { buy_power } from './src/buy_power.js';
import { fetch_cert_address } from './src/hypercert/hypercert.js';
import { mint_hypercert } from './src/blockchain/blockchain.js';
import { mint_nft } from './src/TON/add_ton_sale.js';
import cors from 'cors';


Expand Down Expand Up @@ -111,6 +112,43 @@ app.get('/approve', function (req, res) {
}
})

app.post('/add_ton_asset', async function (req, res) {
const req_data = req.body
console.log("add_asset_req:")
console.log(req_data)


try{
let nft_address = await mint_nft(req_data.provider)
console.log(nft_address)
add_asset(req_data.capacity, nft_address, req_data.date, req_data.type, req_data.location).then(asset_res=>{
console.log("Asset respond:")
console.log(asset_res.result.asset[5].file)
res.send("ok!")
}).catch(err=>{
console.log(err)
res.send("bad")
})
}catch(err){
console.log(err)
res.send("bad")
}
})

app.post('/assets', function (req, res) {
const req_data = req.body
console.log("asset_req:")
console.log(req_data)
try{
search_assets(req_data.address).then(rres=>{
console.log(rres)
res.send(rres)
})
}catch(err){
console.log(err)
}
})


var server = app.listen(8080, function () {

Expand Down
83 changes: 83 additions & 0 deletions apps/backend/src/TON/add_ton_sale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { getitem } from "./search_ton_asset.js";
import { openWallet } from "./src/utils.js";
import { Collection } from "./src/contracts/NftCollection.js";
import { waitSeqno } from "./src/delay.js";
import { Address, toNano } from "ton-core";
import { NftItem } from "./src/contracts/NftItem.js";
import { NftMarketplace } from "./src/contracts/NftMarketplace.js"
import { NftSale } from "./src/contracts/Sales.js";



export async function mint_nft(provider){
const nft = await getitem()
const index = nft.length
try{
let nft_address = await Mint(index)
Salenft(index, provider)
return nft_address
}catch(err){
console.log(err)
}
}

async function Mint(index) {
const wallet = await openWallet(process.env.MNEMONIC.split(" "), true);
const collectionData = {
ownerAddress: wallet.contract.address,
royaltyPercent: 0, // 0.05 = 5%
royaltyAddress: wallet.contract.address,
nextItemIndex: 0,
collectionContentUrl: `ipfs://`,
commonContentUrl: `ipfs://`,
};
const collection = new Collection(collectionData);

console.log(`Start deploy of NFT`);
const mintParams = {
queryId: 0,
itemOwnerAddress: wallet.contract.address,
itemIndex: index,
amount: toNano("0.05"),
commonContentUrl: "",
};

const nftItem = new NftItem(collection);
const seqno = await nftItem.deploy(wallet, mintParams);
console.log(`Successfully deployed NFT`);
await waitSeqno(seqno, wallet);
return (await NftItem.getAddressByIndex(collection.address, index)).toRawString()
}

async function Salenft(index, provider) {
const wallet = await openWallet(process.env.MNEMONIC.split(" "), true);
const collectionData = {
ownerAddress: wallet.contract.address,
royaltyPercent: 0, // 0.05 = 5%
royaltyAddress: wallet.contract.address,
nextItemIndex: 0,
collectionContentUrl: `ipfs://`,
commonContentUrl: `ipfs://`,
};
const collection = new Collection(collectionData);
const marketplace = new NftMarketplace(wallet.contract.address);
const nftToSaleAddress = await NftItem.getAddressByIndex(collection.address, index);

const saleData = {
isComplete: false,
createdAt: Math.ceil(Date.now() / 1000),
marketplaceAddress: marketplace.address,
nftAddress: nftToSaleAddress,
nftOwnerAddress: Address.parse(provider),
fullPrice: toNano("1"),
marketplaceFeeAddress: wallet.contract.address,
marketplaceFee: toNano("0"),
royaltyAddress: wallet.contract.address,
royaltyAmount: toNano("0"),
};
const nftSaleContract = new NftSale(saleData);
const seqno = await nftSaleContract.deploy(wallet);
await waitSeqno(seqno, wallet);

NftItem.transfer(wallet, nftSaleContract.address, nftToSaleAddress);
}
17 changes: 17 additions & 0 deletions apps/backend/src/TON/search_ton_asset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import axios from "axios";


export async function getitem() {
try {
const res = await axios({
method: 'get',
url: `https://testnet.tonapi.io/v2/nfts/collections/EQDW1G_c_xIb2Iyzof123IAzQlY942Pl3H6XEJ_jRB2ez-Pe/items?limit=1000&offset=0`,
})
console.log(res)
return res.data["nft_items"]
}
catch (err) {
console.log("error", err);
}
}

126 changes: 126 additions & 0 deletions apps/backend/src/TON/src/contracts/NftCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
Cell,
internal,
beginCell,
contractAddress,
SendMode,
} from "ton-core";
import { encodeOffChainContent } from "../utils.js";



export class Collection {
collectionData;

constructor(collectionData) {
this.collectionData = collectionData;
}

createCodeCell() {
const NftCollectionCodeBoc =
"te6cckECFAEAAh8AART/APSkE/S88sgLAQIBYgkCAgEgBAMAJbyC32omh9IGmf6mpqGC3oahgsQCASAIBQIBIAcGAC209H2omh9IGmf6mpqGAovgngCOAD4AsAAvtdr9qJofSBpn+pqahg2IOhph+mH/SAYQAEO4tdMe1E0PpA0z/U1NQwECRfBNDUMdQw0HHIywcBzxbMyYAgLNDwoCASAMCwA9Ra8ARwIfAFd4AYyMsFWM8WUAT6AhPLaxLMzMlx+wCAIBIA4NABs+QB0yMsCEsoHy//J0IAAtAHIyz/4KM8WyXAgyMsBE/QA9ADLAMmAE59EGOASK3wAOhpgYC42Eit8H0gGADpj+mf9qJofSBpn+pqahhBCDSenKgpQF1HFBuvgoDoQQhUZYBWuEAIZGWCqALnixJ9AQpltQnlj+WfgOeLZMAgfYBwGyi544L5cMiS4ADxgRLgAXGBEuAB8YEYGYHgAkExIREAA8jhXU1DAQNEEwyFAFzxYTyz/MzMzJ7VTgXwSED/LwACwyNAH6QDBBRMhQBc8WE8s/zMzMye1UAKY1cAPUMI43gED0lm+lII4pBqQggQD6vpPywY/egQGTIaBTJbvy9AL6ANQwIlRLMPAGI7qTAqQC3gSSbCHis+YwMlBEQxPIUAXPFhPLP8zMzMntVABgNQLTP1MTu/LhklMTugH6ANQwKBA0WfAGjhIBpENDyFAFzxYTyz/MzMzJ7VSSXwXiN0CayQ==";
return Cell.fromBase64(NftCollectionCodeBoc);
}

createDataCell() {
const data = this.collectionData;
const dataCell = beginCell();

dataCell.storeAddress(data.ownerAddress);
dataCell.storeUint(data.nextItemIndex, 64);

const contentCell = beginCell();

const collectionContent = encodeOffChainContent(data.collectionContentUrl);

const commonContent = beginCell();
commonContent.storeBuffer(Buffer.from(data.commonContentUrl));

contentCell.storeRef(collectionContent);
contentCell.storeRef(commonContent.asCell());
dataCell.storeRef(contentCell);
const NftItemCodeCell = Cell.fromBase64(
"te6cckECDQEAAdAAART/APSkE/S88sgLAQIBYgMCAAmhH5/gBQICzgcEAgEgBgUAHQDyMs/WM8WAc8WzMntVIAA7O1E0NM/+kAg10nCAJp/AfpA1DAQJBAj4DBwWW1tgAgEgCQgAET6RDBwuvLhTYALXDIhxwCSXwPg0NMDAXGwkl8D4PpA+kAx+gAxcdch+gAx+gAw8AIEs44UMGwiNFIyxwXy4ZUB+kDUMBAj8APgBtMf0z+CEF/MPRRSMLqOhzIQN14yQBPgMDQ0NTWCEC/LJqISuuMCXwSED/LwgCwoAcnCCEIt3FzUFyMv/UATPFhAkgEBwgBDIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7AAH2UTXHBfLhkfpAIfAB+kDSADH6AIIK+vCAG6EhlFMVoKHeItcLAcMAIJIGoZE24iDC//LhkiGOPoIQBRONkchQCc8WUAvPFnEkSRRURqBwgBDIywVQB88WUAX6AhXLahLLH8s/Im6zlFjPFwGRMuIByQH7ABBHlBAqN1viDACCAo41JvABghDVMnbbEDdEAG1xcIAQyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wCTMDI04lUC8ANqhGIu"
);
dataCell.storeRef(NftItemCodeCell);
const royaltyBase = 1000;
const royaltyFactor = Math.floor(data.royaltyPercent * royaltyBase);

const royaltyCell = beginCell();
royaltyCell.storeUint(royaltyFactor, 16);
royaltyCell.storeUint(royaltyBase, 16);
royaltyCell.storeAddress(data.royaltyAddress);
dataCell.storeRef(royaltyCell);

return dataCell.endCell();
}

get stateInit() {
const code = this.createCodeCell();
const data = this.createDataCell();

return { code, data };
}

get address() {
return contractAddress(0, this.stateInit);
}

async deploy(wallet) {
const seqno = await wallet.contract.getSeqno();
await wallet.contract.sendTransfer({
seqno,
secretKey: wallet.keyPair.secretKey,
messages: [
internal({
value: "0.05",
to: this.address,
init: this.stateInit,
}),
],
sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
});
return seqno;
}

async topUpBalance(
wallet,
nftAmount
) {
const feeAmount = 0.026 // approximate value of fees for 1 transaction in our case
const seqno = await wallet.contract.getSeqno();
const amount = nftAmount * feeAmount;

await wallet.contract.sendTransfer({
seqno,
secretKey: wallet.keyPair.secretKey,
messages: [
internal({
value: amount.toString(),
to: this.address.toString({ bounceable: false }),
body: new Cell(),
}),
],
sendMode: SendMode.PAY_GAS_SEPARATELY + SendMode.IGNORE_ERRORS,
});

return seqno;
}

createMintBody(params){
const body = beginCell();
body.storeUint(1, 32);
body.storeUint(params.queryId || 0, 64);
body.storeUint(params.itemIndex, 64);
body.storeCoins(params.amount);
const nftItemContent = beginCell();
nftItemContent.storeAddress(params.itemOwnerAddress);

const uriContent = beginCell();
uriContent.storeBuffer(Buffer.from(params.commonContentUrl));
nftItemContent.storeRef(uriContent.endCell());

body.storeRef(nftItemContent.endCell());
return body.endCell();
}
}
86 changes: 86 additions & 0 deletions apps/backend/src/TON/src/contracts/NftItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Address, beginCell, Cell, internal, SendMode } from "ton-core";
import { TonClient } from "ton";

export class NftItem {
collection;

constructor(collection) {
this.collection = collection;
}

async deploy(
wallet,
params
){
const seqno = await wallet.contract.getSeqno();
await wallet.contract.sendTransfer({
seqno,
secretKey: wallet.keyPair.secretKey,
messages: [
internal({
value: "0.05",
to: this.collection.address,
body: this.collection.createMintBody(params),
}),
],
sendMode: SendMode.IGNORE_ERRORS + SendMode.PAY_GAS_SEPARATELY,
});
return seqno;
}

static async getAddressByIndex(
collectionAddress,
itemIndex
) {
const client = new TonClient({
endpoint: "https://testnet.toncenter.com/api/v2/jsonRPC",
apiKey: process.env.TONCENTER_API_KEY,
});

const response = await client.runMethod(
collectionAddress,
"get_nft_address_by_index",
[{ type: "int", value: BigInt(itemIndex) }]
);
return response.stack.readAddress();
}

static createTransferBody(params) {
const msgBody = beginCell();
msgBody.storeUint(0x5fcc3d14, 32); // op-code
msgBody.storeUint(0, 64); // query-id
msgBody.storeAddress(params.newOwner);
msgBody.storeAddress(params.responseTo || null);
msgBody.storeBit(false); // no custom payload
msgBody.storeCoins(params.forwardAmount || 0);
msgBody.storeBit(0); // no forward_payload

return msgBody.endCell();
}


static async transfer(
wallet,
new_owner,
itemaddress
) {
const seqno = await wallet.contract.getSeqno();
const body = NftItem.createTransferBody({newOwner:new_owner, responseTo: wallet.contract.address})

await wallet.contract.sendTransfer({
seqno,
secretKey: wallet.keyPair.secretKey,
messages: [
internal({
value: "0.05",
to: itemaddress,
body: body,
}),
],
sendMode: SendMode.IGNORE_ERRORS + SendMode.PAY_GAS_SEPARATELY,
});
return seqno;
}


}
Loading

0 comments on commit a184fb4

Please sign in to comment.