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

send jettons #288

Open
F4RD1N opened this issue Oct 19, 2024 · 7 comments
Open

send jettons #288

F4RD1N opened this issue Oct 19, 2024 · 7 comments

Comments

@F4RD1N
Copy link

F4RD1N commented Oct 19, 2024

hi
i want to send jettons programmatically using tonweb.

the transaction will be created but call contract will be failed.

this is my function to sen jettons:
async sendToken(toAddress, tokenContractAddress, tokenAmount, memo) {
try {
const jettonWallet = new TonWeb.token.jetton.JettonWallet(this.tonweb, {
address: tokenContractAddress,
});

  const senderPrivateKey = this.privateKey;

  let seqno = await this.wallet.methods.seqno().call();
  if (seqno === null || seqno === undefined) {
    seqno = 0;
  }

  const amount = TonWeb.utils.toNano(tokenAmount);
  const payload = await jettonWallet.createTransferBody({
    jettonAmount: amount,
    toAddress: new TonWeb.utils.Address(toAddress),
    forwardAmount: TonWeb.utils.toNano("0.1"),
    forwardPayload: new Uint8Array([
      ...new Uint8Array(4),
      ...new TextEncoder().encode(memo),
    ]),
    responseAddress: new TonWeb.utils.Address(process.env.WALLET_ADDRESS),
  });

  const result = await this.wallet.methods
    .transfer({
      secretKey: senderPrivateKey,
      toAddress: tokenContractAddress,
      amount: TonWeb.utils.toNano("0.1"), // TON for transfer fees
      seqno: seqno,
      payload: payload,
      sendMode: 3,
    })
    .send();

  console.log("sendToken Transaction Result:", result);
  return { success: true, result };
} catch (error) {
  console.error("Error sending token:", error.message);
  throw new Error(error.message);
}

}

the payload sent is something like this:
Amount: "100000000000"
CustomPayload: null
Destination: 0:8b023234sdflkjfj409w3929j09jewfdsfd69c1a326463d2f1
ForwardPayload:
IsRight: false
Value:
OpCode: 0
SumType: TextComment
Value:
Text: hello
ForwardTonAmount: "70000000"
QueryId: 0
ResponseDestination: 0:8b0230bf3f6aaf623eb8c15e25d2e6f48ab76d9af9a811d1fwf94w324982

@in-chong
Copy link

Hello, have you solved this problem?

@Rachidfbs
Copy link

[email protected]

@F4RD1N
Copy link
Author

F4RD1N commented Oct 21, 2024

Hello, have you solved this problem?

Yes i have

here the full code:

const { beginCell, Address, TonClient, WalletContractV4, internal, external, storeMessage, toNano } = require( '@ton/ton');
const nacl = require('tweetnacl');
const { mnemonicToWalletKey } = require("ton-crypto");
const apiKey = 'YOUR-API-KEY-HERE';
const client = new TonClient({ endpoint: 'https://toncenter.com/api/v2/jsonRPC', apiKey });

async function getUserJettonWalletAddress(userAddress, contractAddress) {
  const userAddressCell = beginCell().storeAddress(Address.parse(userAddress)).endCell();

  const response = await client.runMethod(Address.parse(contractAddress), 'get_wallet_address', [
    { type: 'slice', cell: userAddressCell },
  ]);

  return response.stack.readAddress();
}


async function getWalletDetails(mnemonic) {
    // Step 1: Get wallet keypair (secretKey and publicKey) from mnemonic
    const formattetMnemonic = mnemonic.split(" ")
    const walletKey = await mnemonicToWalletKey(formattetMnemonic);
    
    const publicKey = walletKey.publicKey;
    const secretKey = walletKey.secretKey;
    
    // Step 2: Create a v4 wallet contract and derive the address
    const wallet = WalletContractV4.create({
        publicKey: publicKey, // Use the public key from the wallet keypair
        workchain: 0 // Usually, the workchain is 0 for normal accounts
    });
    
    const walletAddress = wallet.address;

    return {
        secretKey: secretKey.toString('hex'), // Convert to hex format for readability
        publicKey: publicKey.toString('hex'), // Convert to hex format for readability
        walletAddress: walletAddress.toString() // Get the wallet address as a string
    };
}


const sendToken = async ({mnemonic, recipment, amount, contractAddress}) => {
    const wal = await getWalletDetails(mnemonic)

  const keyPair = nacl.sign.keyPair.fromSecretKey(Buffer.from(wal.secretKey, 'hex'));
  const secretKey = Buffer.from(keyPair.secretKey);
  const publicKey = Buffer.from(keyPair.publicKey);

  const workchain = 0; // Usually you need a workchain 0
  const wallet = WalletContractV4.create({ workchain, publicKey });
  const address = wallet.address.toString({ urlSafe: true, bounceable: false, testOnly: false });
  const contract = client.open(wallet);

  const balance = await contract.getBalance();
//   console.log({ address, balance });

  const seqno = await contract.getSeqno();

  const { init } = contract;
  const contractDeployed = await client.isContractDeployed(Address.parse(address));
  let neededInit = null;

  if (init && !contractDeployed) {
    neededInit = init;
  }

  const jettonWalletAddress = await getUserJettonWalletAddress(address, contractAddress);

//   Comment payload
//   const forwardPayload = beginCell()
//     .storeUint(0, 32) // 0 opcode means we have a comment
//     .storeStringTail('Hello, TON!')
//     .endCell();

  const messageBody = beginCell()
    .storeUint(0xf8a7ea5, 32) // opcode for jetton transfer
    .storeUint(0, 64) // query id
    .storeCoins(amount * 10**9) // jetton amount, amount * 10^9
    .storeAddress(Address.parse(recipment)) // jetton recipient
    .storeAddress(Address.parse(wal.walletAddress)) // response destination
    .storeBit(0) // no custom payload
    .storeCoins(0) // forward amount - if > 0, will send notification message
    .storeBit(0) // we store forwardPayload as a reference, set 1 and uncomment next line for have a comment
    // .storeRef(forwardPayload)
    .endCell();

  const internalMessage = internal({
    to: jettonWalletAddress,
    value: toNano('0.1'),
    bounce: true,
    body: messageBody,
  });

  const body = wallet.createTransfer({
    seqno,
    secretKey,
    messages: [internalMessage],
  });

  const externalMessage = external({
    to: address,
    init: neededInit,
    body,
  });

  const externalMessageCell = beginCell().store(storeMessage(externalMessage)).endCell();

  const signedTransaction = externalMessageCell.toBoc();
  const hash = externalMessageCell.hash().toString('hex');

  await client.sendFile(signedTransaction);

  return {
    hash,
    recipment,
    sender: wal.walletAddress,
    amount
  }
}

(async () => {
  const mnemonic = "YOUR MNEMONIC HERE"
  const recipment = "RECIPIENT ADDRESS HERE"
  const contractAddress = "THE CONTRACT ADDRESS HERE"

  const result = await sendToken({mnemonic, recipment, amount:50, contractAddress})
  console.log(result);
})()

dont forget to set correct opcode of the contract
this is for DOGS:
.storeUint(0xf8a7ea5, 32)

the code perfectly works for me but if didnt work for you check this part of code:
to: jettonWalletAddress,

the value of "to" is my jetton wallet and i think it must be recipment jetton address. or im wrong because the code works fine

@khalilmosavi
Copy link

khalilmosavi commented Oct 21, 2024 via email

@khalilmosavi
Copy link

khalilmosavi commented Oct 22, 2024 via email

@F4RD1N
Copy link
Author

F4RD1N commented Oct 22, 2024

you dont need to send me anything
all you need is a simple knowledge of javascript and thats it. the code i sent to you is easy to read and use. but if you dont understrand javascript at all, unfortunately it cannot helps you. i made the code easy to use for you
you just need an API key, your 24 phrase key of the wallet you want to transfer tokens, recipment wallet address and token contract address( Master)
if you dont know all of these stuff you should learn some javascript and need a little bit knowledge of working with ton wallet addresses and jetton transfer in blockchain

@khalilmosavi
Copy link

khalilmosavi commented Oct 22, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants