import BN from "bn.js"; import {Address, beginCell, Cell, contractAddress, TonClient, WalletContract, WalletV3R2Source} from "ton"; import {mnemonicToWalletKey} from "ton-crypto"; // encode contract storage according to save_data() contract method // storage#_ total_supply:Coins admin_address:MsgAddress next_admin_address:MsgAddress content:^Cell jetton_wallet_code:^Cell = Storage; export function minterData(params: { adminAddress: Address; supply: number, nextAdminAddress?: Address, content: Cell, wallet_code: Cell }): Cell { if (!params.nextAdminAddress) params.nextAdminAddress = params.adminAddress; return beginCell() .storeCoins(params.supply) .storeAddress(params.adminAddress) .storeAddress(params.nextAdminAddress) .storeRef(params.content) .storeRef(params.wallet_code) .endCell(); } function bufferToChunks(buff: Buffer, chunkSize: number) { let chunks: Buffer[] = [] while (buff.byteLength > 0) { chunks.push(buff.slice(0, chunkSize)) buff = buff.slice(chunkSize) } return chunks } export function makeSnakeCell(data: Buffer) { let chunks = bufferToChunks(data, 127) let rootCell = new Cell() let curCell = rootCell for (let i = 0; i < chunks.length; i++) { let chunk = chunks[i] curCell.bits.writeBuffer(chunk) if (chunks[i + 1]) { let nextCell = new Cell() curCell.refs.push(nextCell) curCell = nextCell } } return rootCell } export function getMinterAddress(params: { adminAddress: Address; supply: number, nextAdminAddress?: Address, content: Cell, wallet_code: Cell }, initCodeCell: Cell): Address { return contractAddress({workchain: 0, initialData: minterData(params), initialCode: initCodeCell}); } const OFF_CHAIN_CONTENT_PREFIX = 0x01 export function encodeOffChainContent(content: string) { let data = Buffer.from(content) let offChainPrefix = Buffer.from([OFF_CHAIN_CONTENT_PREFIX]) data = Buffer.concat([offChainPrefix, data]) return makeSnakeCell(data) } // storage#_ balance:(VarUInteger 16) owner_address:MsgAddressInt jetton_master_address:MsgAddressInt jetton_wallet_code:^Cell = Storage; export function walletData(params: { balance: number, ownerAddress: Address, jettonMasterAddress: Address, jettonWalletCode: Cell }): Cell { return beginCell() .storeUint(params.balance, 15) .storeAddress(params.ownerAddress) .storeAddress(params.jettonMasterAddress) .storeRef(params.jettonWalletCode) .endCell(); } export function getJettonAddress(ownerAddress: Address, jettonMasterAddress: Address, jettonWalletCode: Cell): Address { return contractAddress({ workchain: 0, initialData: walletData({balance: 0, ownerAddress, jettonMasterAddress, jettonWalletCode}), initialCode: jettonWalletCode }); } export function transferMsg(amount: number, recipient: Address) { return beginCell() .storeUint(0xf8a7ea5, 32) .storeUint(0, 64) .storeCoins(amount) .storeAddress(recipient) .storeAddress(recipient) .storeBit(false) .storeCoins(0) .storeBit(false) .endCell(); } export function TON(): number { return 1000000000; } // message encoders for all ops (see contracts/imports/constants.fc for consts) export function depositMsg(amount: number): Cell { return beginCell().storeUint(0x77a33521, 32) .storeUint(0, 64).storeCoins(amount).endCell(); } export function withdrawMsg(amount: BN | number): Cell { return beginCell().storeUint(0x47d1895f, 32).storeUint(0, 64).storeCoins(amount).endCell(); } export async function getWallet(isTestnet: boolean = true) { const client = new TonClient({ endpoint: `https://${isTestnet ? "testnet." : ""}toncenter.com/api/v2/jsonRPC`, apiKey: isTestnet ? 'bed2b4589201ff3c575be653593f912a337c08eed416b60b02345763b9ee9c36' : 'a1e8a1055a387515158589dc7e9bad3035e7db2b9f9ea5cdad6b727f71e328db' }); let deployerMnemonic = process.env.DEPLOYER_MNEMONIC; if (!deployerMnemonic) throw new Error("DEPLOYER_MNEMONIC env var is not set"); // open the wallet and make sure it has enough TON const walletKey = await mnemonicToWalletKey(deployerMnemonic.split(" ")); let workchain = 0; return [WalletContract.create(client, WalletV3R2Source.create({ publicKey: walletKey.publicKey, workchain })), walletKey]; }