ton-blockchain / minter

Jetton Deployer Frontend
MIT License
147 stars 91 forks source link

Issue: Unable to Deploy Airdrop Contract with Proper stateInit and Payload #200

Open rishabh259jain opened 1 week ago

rishabh259jain commented 1 week ago

Description I'm trying to deploy the airdrop contract from the Gusarich/airdrop repository. I have compiled the contract on the backend and am attempting to deploy it via the frontend using TonConnectUI. However, I am unable to successfully activate the contract, as it remains in a nonexistent state upon deployment.

Frontend and Backend Setup Frontend Deployment: I'm using TonConnectUI to send the transaction with the stateInit and payload. Backend Compilation: The contract code and initial setup are compiled on the backend, and I'm sending relevant data like the stateInit, airdropContractAddress, merkleRoot, helperCode, and jettonWallet to the frontend.

Problem Details The deployment transaction shows as failed or nonexistent. I’m following the TON documentation guidelines on preparing messages and constructing the stateInit and payload cells, but the contract does not reach the active state. Specific error messages or log output indicate deployment issues, such as "Deployment error" and "Failed to deploy the contract."

Code Snippet Here is a simplified version of my frontend code for deploying the contract:

import {
  TonConnectButton,
  useTonAddress,
  useTonConnectUI,
} from "@tonconnect/ui-react";
import "./style.css";
import { Address, beginCell, toNano, Cell, StateInit } from "ton";
import BN from "bn.js";
import { useState } from "react";

// Specify gas required for deployment
export const DEPLOY_GAS = toNano("0.1");

export default function App() {
  const [ad, setAd] = useState("");
  const walletAddress = useTonAddress();
  const [tonConnectUI] = useTonConnectUI();

  async function deployContract() {
    try {
      const ownerAddress = Address.parse(walletAddress);

      // Data from backend (including contract and helper hex codes)
      const data = {
        airdropContractAddress: 'EQAJwHyLqmRXMOHxmvKVUuDdNyvJ7ykxKCCRspSGuYiyqQmL',
        dictCellBase64: 'te6cckEBAQEAKgAAT9AIAKgfVaKEoRubk9A4zPefVG54jrtSl7fQ9njAO8ULsU4SjuaygBBi5I1J',
        merkleRoot: 92809725053853176027830988708193645447941139483491440242080957149474509985528n,
        jettonWallet: 'EQDXH7cdc17Lnz8VxU5pfHNpsyb68lLkd7iHw8kWc5V0sq8I',
        helperCodeHex: 'b5ee9c7241010701008a000114ff00f4a413f4bcf2c80b01020120040201bef26c2101821005f5e100bef2e2c0ed44d0d20001f2d2be88ed54fa40d3ffd3ff3003d33fd43020f9005003baf2e2c1f800820afaf08070fb02821043c7d5c9c8cb1fcb3fcc12cbffc9718010c8cb055003cf1670fa0212cb6accc98306fb00030001c002014806050011a098d7da89a1ae14010002d0289d180d',
        airdropCodeHex: 'b5ee9c7241020b01000151000114ff00f4a413f4bcf2c80b0102016203020033a0df8dda89a1f48003f0c3a7fe03f0c5a861f0c7f083f085f0870202cc09040201480605007747020f84682100f8a7ea5c8cb1fcb3f5003fa0223cf165003cf16cb008208989680fa02cb00c9718018c8cb05f841cf1670fa02cb6accc98040fb008020120080700173e4020c27232c2b2fff27420002f1c3232c03e0a33c584b2fff2fff27e10ddb232c13333326001b5db611106ba4e0b048adf0698f80fc32699f80fc3300e83a6b90fd20187c32f6a2687d2000fc30e9ff80fc316a187c31fc224108308652365d470f7c20eb8580e0007971617d20187c30fc21fc21647c20e78b65ffe664f6aa718740a009cf844821043c7d5c9ba8e3cd4d3ff3021d739f2aad30701c003f2abf84201d3ff59baf2acd43052108307f40e6fa1f2adf84503f90058f008f00912c705f2e2bffa40fa0030f00a9530840ff2f0e2a6b76e5a'
      };

      // Convert hex to BOC for helper code and main contract code
      const helperCode = Cell.fromBoc(Buffer.from(data.helperCodeHex, "hex"))[0];
      const codeCell = Cell.fromBoc(Buffer.from(data.airdropCodeHex, "hex"))[0];

      // Ensure `jettonWallet` is parsed as an Address
      const jettonWalletAddress = Address.parse(data.jettonWallet);

      // Create the initialization data cell (`dataCell`)
      const dataCell = beginCell()
        .storeUint(0, 2)
        .storeUint(new BN(data.merkleRoot.toString()), 256)
        .storeRef(helperCode)
        .storeUint(Math.floor(Math.random() * 1e9), 64)
        .endCell();

      // Construct the `stateInit` with code and data
      const stateInitCell = new Cell();
      new StateInit({ data: dataCell, code: codeCell }).writeTo(stateInitCell);

      // Create deployment payload
      const deploymentCell = beginCell()
        .storeUint(0x610ca46c, 32)
        .storeUint(0, 64)
        .storeAddress(jettonWalletAddress)
        .endCell();

      // Prepare the transaction for TonConnectUI
      const transaction = {
        validUntil: Math.floor(Date.now() / 1000) + 300,
        messages: [
          {
            address: airdropContractAddress,
            amount: DEPLOY_GAS.toString(),
            stateInit: stateInitCell.toBoc().toString("base64"),
            payload: deploymentCell.toBoc().toString("base64"),
            bounce: false,
          },
        ],
      };

      await tonConnectUI.sendTransaction(transaction);
      setAd(airdropContractAddress);
    } catch (error) {
      console.error("Deployment error:", error);
    }
  }

  return (
    <div style={{ display: "flex", gap: 20, flexDirection: "column" }}>
      <TonConnectButton />
      <button onClick={deployContract}>Deploy Contract</button>
      <div style={{ maxWidth: "500px", overflow: "auto", marginTop: "10px" }}>
        {ad}
      </div>
    </div>
  );
}

Additional Context I have followed the official TON documentation for preparing messages for TonConnect. I am not sure if the stateInit and payload cells are being constructed correctly for this contract. I have tried using both hex-based and BOC-based approaches, but the deployment consistently fails. I have tested with hardcoded values from the backend to ensure data consistency.

Request Could you please help review the approach to constructing the stateInit and payload cells? Is there any specific nuance in the airdrop contract deployment process that differs from standard TON deployments?

Thank you for any insights you can provide!