Browse Source

jetton-helpers

master
AlexG 2 years ago
parent
commit
23fe2db2fa
  1. 21
      sources/jetton.deploy.ts
  2. 122
      sources/utils/jetton-helpers.ts

21
sources/jetton.deploy.ts

@ -1,12 +1,25 @@
import { beginCell, contractAddress, toNano, TonClient, TonClient4, Address, WalletContractV4, internal, fromNano} from "ton";
import {mnemonicToPrivateKey} from "ton-crypto";
import { packAdd, init } from "./output/jetton_SampleJetton";
import { printAddress, printDeploy, printHeader } from "./utils/print";
import { randomAddress } from "./utils/randomAddress";
import {SampleJetton_errors} from "./output/jetton_SampleJetton";
import {JettonMetaDataKeys} from 'utils/jetton-helpers';
(async () => { //need changes for jetton
// This is example data - Modify these params for your own jetton!
// - Data is stored on-chain (except for the image data itself)
// - Owner should usually be the deploying wallet's address.
const jettonParams = {
name: "MyJetton",
symbol: "JET1",
image: "https://www.linkpicture.com/q/download_183.png", // Image url
description: "My jetton",
};
//create client for testnet Toncenter API
const client = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',

122
sources/utils/jetton-helpers.ts

@ -1,37 +1,99 @@
import { Cell, beginCell, Address, beginDict, Slice, toNano } from "ton";
import {Address, Cell, Builder, beginCell} from "ton";
let contentSlice2 : Slice;
const ONCHAIN_CONTENT_PREFIX = 0x00;
const SNAKE_PREFIX = 0x00;
export type JettonMetaDataKeys = "name" | "description" | "image" | "symbol";
const jettonOnChainMetadataSpec: {
[key in JettonMetaDataKeys]: "utf8" | "ascii" | undefined;
} = {
name: "utf8",
description: "utf8",
image: "ascii",
symbol: "utf8",
};
enum OPS {
ChangeAdmin = 3,
ReplaceMetadata = 4,
Mint = 21,
InternalTransfer = 0x178d4519,
Transfer = 0xf8a7ea5,
Burn = 0x595f07bc,
const sha256 = (str: string) => {
const sha = new Sha256();
sha.update(str);
return Buffer.from(sha.digestSync());
};
export function buildTokenMetadataCell(data: { [s: string]: string | undefined }): Cell {
const KEYLEN = 256;
let rootCell = beginCell();
let dict = new Cell();
Object.entries(data).forEach(([k, v]: [string, string | undefined]) => {
if (!jettonOnChainMetadataSpec[k as JettonMetaDataKeys])
throw new Error(`Unsupported onchain key: ${k}`);
if (v === undefined || v === "") return;
let bufferToStore = Buffer.from(v, jettonOnChainMetadataSpec[k as JettonMetaDataKeys]);
const CELL_MAX_SIZE_BYTES = Math.floor((1023 - 8) / 8);
rootCell.storeUint(SNAKE_PREFIX, 16);
let currentCell = rootCell;
//TODO need fix dictionary writing
while (bufferToStore.length > 0) {
currentCell.storeBits(bufferToStore.read(CELL_MAX_SIZE_BYTES)) // how to read from Buffer???
//currentCell.bits.writeBuffer(bufferToStore.slice(0, CELL_MAX_SIZE_BYTES));
//bufferToStore = bufferToStore.slice(CELL_MAX_SIZE_BYTES);
if (bufferToStore.length > 0) {
const newCell = new Builder();
newCell.storeRef(currentCell);
currentCell = newCell;
}
}
let dict = currentCell.endCell();
});
return beginCell().storeInt(ONCHAIN_CONTENT_PREFIX, 8).storeDict(dict).endCell();
}
export type JettonMetaDataKeys =
| "name"
| "description"
| "image"
| "symbol"
| "image_data"
| "decimals";
async function parseJettonOffchainMetadata(contentSlice: Slice): Promise<{
metadata: { [s in JettonMetaDataKeys]?: string };
isIpfs: boolean;
}> {
const jsonURI = contentSlice
.loadBits(await () => (contentSlice.remainingBits()))
.toString("ascii")
.replace("ipfs://", "https://ipfs.io/ipfs/");
return {
metadata: (await axios.get(jsonURI)).data,
isIpfs: /(^|\/)ipfs[.:]/.test(jsonURI),
};
export function parseTokenMetadataCell(contentCell: Cell): {
[s in JettonMetaDataKeys]?: string;
} {
// Note that this relies on what is (perhaps) an internal implementation detail:
// "ton" library dict parser converts: key (provided as buffer) => BN(base10)
// and upon parsing, it reads it back to a BN(base10)
// tl;dr if we want to read the map back to a JSON with string keys, we have to convert BN(10) back to hex
const toKey = (str: string) => new BN(str, "hex").toString(10);
const KEYLEN = 256;
const contentSlice = contentCell.beginParse();
if (contentSlice.readUint(8).toNumber() !== ONCHAIN_CONTENT_PREFIX)
throw new Error("Expected onchain content marker");
const dict = contentSlice.readDict(KEYLEN, (s) => {
const buffer = Buffer.from("");
const sliceToVal = (s: Slice, v: Buffer, isFirst: boolean) => {
s.toCell().beginParse();
if (isFirst && s.readUint(8).toNumber() !== SNAKE_PREFIX)
throw new Error("Only snake format is supported");
v = Buffer.concat([v, s.readRemainingBytes()]);
if (s.remainingRefs === 1) {
v = sliceToVal(s.readRef(), v, false);
}
return v;
};
return sliceToVal(s.readRef(), buffer, true);
});
const res: { [s in JettonMetaDataKeys]?: string } = {};
Object.keys(jettonOnChainMetadataSpec).forEach((k) => {
const val = dict
.get(toKey(sha256(k).toString("hex")))
?.toString(jettonOnChainMetadataSpec[k as JettonMetaDataKeys]);
if (val) res[k as JettonMetaDataKeys] = val;
});
return res;
}
Loading…
Cancel
Save