Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: frontend_arch #76

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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