diff --git a/src/App.tsx b/src/App.tsx index cbdf461..adcdee6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import {Header} from "./Header.tsx"; import {Content} from "./Content.tsx"; function App() { - return + return
diff --git a/src/Content.tsx b/src/Content.tsx index ad59c88..320435a 100644 --- a/src/Content.tsx +++ b/src/Content.tsx @@ -30,6 +30,6 @@ export const Content = () => { src="https://raw.githubusercontent.com/mir-one/sbt-scanner/main/public/scanner.gif" style={{ display: 'block', width: '144px', height: '144px' }} /> - + } \ No newline at end of file diff --git a/src/assets/nft.ts b/src/assets/nft.ts new file mode 100644 index 0000000..8466378 --- /dev/null +++ b/src/assets/nft.ts @@ -0,0 +1,121 @@ +import { Base64 } from "@tonconnect/protocol"; +import { + Address, + beginCell, + contractAddress as calculateContractAddress, + Cell, + storeStateInit, +} from "ton"; + +const nftUri = + "https://raw.githubusercontent.com/mir-one/sbt-scanner/main/public/nft.json"; + +function bufferToChunks(buff: Buffer, chunkSize: number) { + const chunks: Buffer[] = []; + while (buff.byteLength > 0) { + chunks.push(buff.subarray(0, chunkSize)); + buff = buff.subarray(chunkSize); + } + return chunks; +} + +function makeSnakeCell(data: Buffer): Cell { + const chunks = bufferToChunks(data, 127); + + if (chunks.length === 0) { + return beginCell().endCell(); + } + + if (chunks.length === 1) { + return beginCell().storeBuffer(chunks[0]).endCell(); + } + + let curCell = beginCell(); + + for (let i = chunks.length - 1; i >= 0; i--) { + const chunk = chunks[i]; + + curCell.storeBuffer(chunk); + + if (i - 1 >= 0) { + const nextCell = beginCell(); + nextCell.storeRef(curCell); + curCell = nextCell; + } + } + + return curCell.endCell(); +} + +const contractCode = + "te6cckECDgEAAdwAART/APSkE/S88sgLAQIBYgINAgLOAwoCASAECQLPDIhxwCSXwPg0NMDAXGwkl8D4PpA+kAx+gAxcdch+gAx+gAwc6m0APACBLOOFDBsIjRSMscF8uGVAfpA1DAQI/AD4AbTH9M/ghBfzD0UUjC64wIwNDQ1NYIQL8smohK64wJfBIQP8vCAFCAKsMhA3XjJAE1E1xwXy4ZH6QCHwAfpA0gAx+gAg10nCAPLixIIK+vCAG6EhlFMVoKHeItcLAcMAIJIGoZE24iDC//LhkiGUECo3W+MNApMwMjTjDVUC8AMGBwB8ghAFE42RyFAJzxZQC88WcSRJFFRGoHCAEMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAEEcAaibwAYIQ1TJ22xA3RABtcXCAEMjLBVAHzxZQBfoCFctqEssfyz8ibrOUWM8XAZEy4gHJAfsAAHJwghCLdxc1BcjL/1AEzxYQJIBAcIAQyMsFUAfPFlAF+gIVy2oSyx/LPyJus5RYzxcBkTLiAckB+wAAET6RDBwuvLhTYAIBIAsMADs7UTQ0z/6QCDXScIAmn8B+kDUMBAkECPgMHBZbW2AAHQDyMs/WM8WAc8WzMntVIAAJoR+f4AUR8jb8"; +const initCodeCell = Cell.fromBase64(contractCode); + +const createOffchainUriCell = (uri: string) => { + let data = Buffer.from(uri); + const offChainPrefix = Buffer.from([0x01]); + data = Buffer.concat([offChainPrefix, data]); + return makeSnakeCell(data); +}; + +function generateInitialData(ownerAddressHex: string): Cell { + const nftContent = createOffchainUriCell(nftUri); + + const builder = beginCell() + .storeUint(0, 64) + .storeUint(0, 2) + .storeAddress(Address.parseRaw(ownerAddressHex)) + .storeUint(Date.now(), 64) + .storeRef(nftContent); + + return builder.endCell(); +} + +function generateStateInit(data: Cell): string { + return callToBase64( + beginCell() + .store(storeStateInit({ code: initCodeCell, data })) + .endCell() + ); +} + +function callToBase64(cell: Cell): string { + return Base64.encode(cell.toBoc()); +} + +function generateContractAddress(initDataCell: Cell): string { + return calculateContractAddress(0, { + data: initDataCell, + code: initCodeCell, + }).toString(); +} + +export function getAddressAndStateInit(ownerAddress: string): { + address: string; + stateInit: string; +} { + const initialData = generateInitialData(ownerAddress); + const address = generateContractAddress(initialData); + const stateInit = generateStateInit(initialData); + return { address, stateInit }; +} + +export function generatePayload(sendTo: string): string { + const op = 0x5fcc3d14; // transfer + const quiryId = 0; + const messageBody = beginCell() + .storeUint(op, 32) + .storeUint(quiryId, 64) + .storeAddress(Address.parse(sendTo)) + .storeAddress(Address.parse(sendTo)) + .storeBit(false) + .storeCoins(0) + .storeBit(0) + .endCell(); + + return Base64.encode(messageBody.toBoc()); +} + +export function getRawAddress(userFriendlyAddress: string): string { + return Address.parse(userFriendlyAddress).toString(); +}