How can I mint a Hedera token that is not owned by the contract I am using to mint it? - solidity

I want to mint a Hedera Token with a smart contract. This token is not owned by the smart contract I am writing. I have been told on the Discord to 'put the private key in the contract' but this is not very specific and feels weird. The mintToken function provided in the Hedera Token Service takes as parameter:
an address
an amount
some metadata in the case of NFTs.

It's not impossible to mint a token made of a smart contract with HederaTokenService.
You may use a smart contract to make a token on hedera like ERC-20 or ERC-721, they works but they are not recognized as tokens in hedera network.
You have to use HederaTokenService to make a token on hedera.
You can use a smart contract using HederaTokenService interface(its address is 0x167) or transactions like below.
You seems using HederaTokenService.sol.
The second parameter only has meaning when you mint a fungible token.
And the second parameter only has meaning when you mint a non-funtible token.
You can create a fungible token and mint like this.
IHederaTokenService.TokenKey[]
memory keys = new IHederaTokenService.TokenKey[](1);
// Set this contract as supply
keys[0] = getSingleKey(
KeyType.SUPPLY,
KeyValueType.CONTRACT_ID,
address(this)
);
IHederaTokenService.HederaToken memory token;
token.name = _name;
token.symbol = _symbol;
token.treasury = address(this);
token.memo = _memo;
token.tokenSupplyType = true; // set supply to FINITE
token.maxSupply = _maxSupply;
token.freezeDefault = false;
token.tokenKeys = keys;
token.expiry = createAutoRenewExpiry(address(this), _autoRenewPeriod); // Contract automatically renew by himself
(int256 responseCode, address createdToken) = HederaTokenService
.createFungibleToken(token, 0, _decimals);
if (responseCode != HederaResponseCodes.SUCCESS) {
revert("Failed to create fungible token");
}
tokenAddress = createdToken;
(int256 response, uint64 newSupply, ) = HederaTokenService.mintToken(
tokenAddress,
uint64(amount),
new bytes[](0)
);
Or a Non-fungible token like this.
IHederaTokenService.TokenKey[]
memory keys = new IHederaTokenService.TokenKey[](2);
// Set this contract as supply
keys[0] = getSingleKey(
KeyType.SUPPLY,
KeyValueType.CONTRACT_ID,
address(this)
);
keys[1] = getSingleKey(
KeyType.PAUSE,
KeyValueType.CONTRACT_ID,
address(this)
);
IHederaTokenService.HederaToken memory token;
token.name = _name;
token.symbol = _symbol;
token.treasury = address(this);
token.memo = _memo;
token.tokenSupplyType = true; // set supply to FINITE
token.maxSupply = int64(int256(_maxSupply));
token.freezeDefault = false;
token.tokenKeys = keys;
token.expiry = createAutoRenewExpiry(address(this), _autoRenewPeriod); // Contract automatically renew by himself
(int256 responseCode, address createdToken) = HederaTokenService
.createNonFungibleToken(token);
if (responseCode != HederaResponseCodes.SUCCESS) {
revert("Failed to create non-fungible token");
}
tokenAddress = createdToken;
(int256 response, uint64 newSupply, ) = HederaTokenService.mintToken(
tokenAddress,
uint64(amount),
new bytes[](0)
);
(int256 response, , int64[] memory serialNumbers) = HederaTokenService
.mintToken(tokenAddress, 0, metadata);
Here is a code of using transactions.
Hope it will help you.
const {
Client,
AccountId,
AccountBalanceQuery,
ContractExecuteTransaction,
ContractFunctionParameters,
ContractCallQuery,
TokenCreateTransaction,
Hbar,
HbarUnit,
TransactionRecord,
TokenSupplyType,
TokenType,
PrivateKey,
AccountCreateTransaction,
TokenId,
TokenMintTransaction,
TokenAssociateTransaction,
TokenDissociateTransaction,
TransferTransaction,
} = require("#hashgraph/sdk");
// Allow access to ourenv file variables
require("dotenv").config();
const print = require("./utils.js").print;
// Grab your account ID and private key from the .env file
const operatorAccountId = AccountId.fromString(process.env.MY_ACCOUNT_ID);
const operatorPrivateKey = PrivateKey.fromString(process.env.MY_PRIVATE_KEY);
const operatorPublicKey = operatorPrivateKey.publicKey;
const treasuryId = AccountId.fromString(process.env.TREASURY_ID);
const treasuryKey = PrivateKey.fromString(process.env.TREASURY_PVKEY);
const aliceId = AccountId.fromString(process.env.ALICE_ID);
const aliceKey = PrivateKey.fromString(process.env.ALICE_PVKEY);
const supplyKey = PrivateKey.fromString(process.env.SUPPLY_PVKEY);
const tokenId = TokenId.fromString("0.0.*");
// If we weren't able to grab it, we should throw a new error
if (operatorPrivateKey == null || operatorAccountId == null) {
throw new Error(
"environment variables MY_ACCOUNT_ID and MY_PRIVATE_KEY must be present"
);
}
// Create our connection to the Hedera network
// The Hedera JS SDK makes this really easy!
const client = Client.forTestnet();
// Set your client account ID and private key used to pay for transaction fees and sign transactions
client.setOperator(operatorAccountId, operatorPrivateKey);
async function printBalance(accountAlias, accountId) {
var currentBalance = await new AccountBalanceQuery()
.setAccountId(accountId.toString())
.execute(client);
console.log(
`Balance of ${accountAlias} (accountId ${accountId}): ${currentBalance.toString()}`
);
}
async function queryContract() {
const tx = new ContractCallQuery()
.setGas(300000)
.setContractId(tokenId.toString())
.setFunction(
"tokenURI",
new ContractFunctionParameters().addUint256(12)
// .addString("Golden")
);
// .setQueryPayment(Hbar.fromTinybars(300000));
const contractFunctionResult = await tx.execute(client);
console.log();
const ret_0 = contractFunctionResult.getString(0);
console.log(`return value :>> ${ret_0.toString()}`);
}
async function generateKey() {
const privateKey = await PrivateKey.generateED25519Async();
console.log(
`New key generated.\nPublic Key is ${privateKey.publicKey}\nPrivateKey is ${privateKey}`
);
return privateKey;
}
async function createAccount() {
const privateKey = await generateKey();
const transaction = new AccountCreateTransaction()
.setKey(privateKey.publicKey)
.setInitialBalance(new Hbar(1000));
//Sign the transaction with the client operator private key and submit to a Hedera network
const txResponse = await transaction.execute(client);
//Request the receipt of the transaction
const receipt = await txResponse.getReceipt(client);
//Get the account ID
const newAccountId = receipt.accountId;
console.log("The new account ID is " + newAccountId);
}
async function writeContract() {
const tx = new ContractExecuteTransaction()
.setContractId(contractId)
.setGas(300000) // Increase if revert
.setPayableAmount(Hbar.from(1.00000001)) // Increase if revert
.setFunction("pay", new ContractFunctionParameters().addString("Donate"));
const txRes = await tx.execute(client);
print("txResponse", txRes);
const receipt = await txRes.getReceipt(client);
print("recepit", receipt);
const txRec = await txRes.getRecord(client);
print("txRecord", txRec);
const value = txRec.contractFunctionResult.getUint256(0);
console.log(`First return value is: ${value.toString()}`);
const ret_0 = txRec.contractFunctionResult.getString(1);
console.log(`second return value is: ${ret_0.toString()}`);
// console.log(`First return value is: ${AccountId.fromSolidityAddress(ret_0)}`);
}
async function createToken() {
const transaction = await new TokenCreateTransaction()
.setTokenName("My Token")
.setTokenSymbol("MYT")
.setTokenType(TokenType.NonFungibleUnique)
.setDecimals(0)
.setInitialSupply(0)
.setTreasuryAccountId(treasuryId)
.setSupplyType(TokenSupplyType.Finite)
.setMaxSupply(1000)
.setSupplyKey(supplyKey)
.freezeWith(client);
//Sign the transaction with the token adminKey and the token treasury account private key
const signTx = await transaction.sign(treasuryKey);
//Sign the transaction with the client operator private key and submit to a Hedera network
const txRes = await signTx.execute(client);
print("txResponse", txRes);
const receipt = await txRes.getReceipt(client);
print("recepit", receipt);
const txRec = await txRes.getRecord(client);
print("txRecord", txRec);
//Get the token ID
let tokenId = receipt.tokenId;
//Log the token ID
console.log(`- Created NFT with Token ID: ${tokenId} \n`);
}
async function mintToken() {
// Mint new NFT
let mintTx = await new TokenMintTransaction()
.setTokenId(tokenId)
.setMetadata([
Buffer.from(
"A METADATA LINK"
),
])
.freezeWith(client);
//Sign the transaction with the supply key
let mintTxSign = await mintTx.sign(supplyKey);
print("Singed Tx", mintTxSign);
//Submit the transaction to a Hedera network
let minttxRes = await mintTxSign.execute(client);
print("Tx Response", minttxRes);
//Get the transaction receipt
let mintRx = await minttxRes.getReceipt(client);
print("Tx Receipt", mintRx);
//Get the transaction record
let mintRec = await minttxRes.getRecord(client);
print("Tx Record", mintRec);
//Log the serial number
console.log(
`- Created NFT ${tokenId} with serial: ${mintRx.serials[0].low} \n`
);
}
async function associateToken(tokenIds) {
//Create the associate transaction and sign with Alice's key
let tx = await new TokenAssociateTransaction()
.setAccountId(aliceId)
.setTokenIds(tokenIds)
.freezeWith(client)
.sign(aliceKey);
//Submit the transaction to a Hedera network
let txRes = await tx.execute(client);
print("Tx Response", txRes);
//Get the transaction receipt
let txRx = await txRes.getReceipt(client);
print("Tx Receipt", txRx);
//Get the transaction record
let txRec = await txRes.getRecord(client);
print("Tx Record", txRec);
//Confirm the transaction was successful
console.log(`- NFT association with Alice's account: ${txRx.status}\n`);
}
async function dissociateToken(tokenIds) {
//Create the associate transaction and sign with Alice's key
let tx = await new TokenDissociateTransaction()
.setAccountId(operatorAccountId)
.setTokenIds(tokenIds)
.freezeWith(client)
.sign(aliceKey);
//Submit the transaction to a Hedera network
let txRes = await tx.execute(client);
print("Tx Response", txRes);
//Get the transaction receipt
let txRx = await txRes.getReceipt(client);
print("Tx Receipt", txRx);
//Get the transaction record
let txRec = await txRes.getRecord(client);
print("Tx Record", txRec);
//Confirm the transaction was successful
console.log(`- NFT association with Alice's account: ${txRx.status}\n`);
}
async function transferToken() {
// Check the balance before the transfer for the treasury account
var balanceCheckTx = await new AccountBalanceQuery()
.setAccountId(treasuryId)
.execute(client);
console.log(
`- Treasury balance: ${balanceCheckTx.tokens._map.get(
tokenId.toString()
)} NFTs of ID ${tokenId}`
);
// Check the balance before the transfer for Alice's account
var balanceCheckTx = await new AccountBalanceQuery()
.setAccountId(aliceId)
.execute(client);
console.log(
`- Alice's balance: ${balanceCheckTx.tokens._map.get(
tokenId.toString()
)} NFTs of ID ${tokenId}`
);
// Transfer the NFT from treasury to Alice
// Sign with the treasury key to authorize the transfer
let tokenTransferTx = await new TransferTransaction()
.addNftTransfer(tokenId, 2 /*SN*/, treasuryId, aliceId)
.freezeWith(client)
.sign(treasuryKey);
let tokenTransferSubmit = await tokenTransferTx.execute(client);
print("Tx Response", tokenTransferSubmit);
let tokenTransferRx = await tokenTransferSubmit.getReceipt(client);
print("Tx Receipt", tokenTransferRx);
let tokenTransferRec = await tokenTransferSubmit.getRecord(client);
print("Tx Record", tokenTransferRec);
console.log(
`\n- NFT transfer from Treasury to Alice: ${tokenTransferRx.status} \n`
);
// Check the balance of the treasury account after the transfer
var balanceCheckTx = await new AccountBalanceQuery()
.setAccountId(treasuryId)
.execute(client);
console.log(
`- Treasury balance: ${balanceCheckTx.tokens._map.get(
tokenId.toString()
)} NFTs of ID ${tokenId}`
);
// Check the balance of Alice's account after the transfer
var balanceCheckTx = await new AccountBalanceQuery()
.setAccountId(aliceId)
.execute(client);
console.log(
`- Alice's balance: ${balanceCheckTx.tokens._map.get(
tokenId.toString()
)} NFTs of ID ${tokenId}`
);
}
// Hedera is an asynchronous environment :)
(async function () {
await printBalance("Operator", operatorAccountId);
try {
// await printBalance("Treasury", treasuryId);
// await createAccount();
// await generateKey();
// await createToken();
// await mintToken();
// await associateToken();
// await dissociateToken();
// await transferToken();
// await queryContract();
// await writeContract();
// await printBalance("Treasury", treasuryId);
} catch (err) {
console.error(err);
}
await printBalance("Operator", operatorAccountId);
process.exit();
})();

Related

using hardhat test transfer USDC to my contract have bug

function depositETH() public payable returns (bool) {
// 应该是先把ETH存入该合约中,然后把该合约的资产存入到compound中
CEth cToken = CEth(cETH);
// Amount of current exchange rate from cToken to underlying
uint256 exchangeRateMantissa = cToken.exchangeRateCurrent();
emit TradeLog(
"Exchange Rate (scaled up by 1e18): ",
exchangeRateMantissa
);
// Amount added to you supply balance this block
uint256 supplyRateMantissa = cToken.supplyRatePerBlock();
emit TradeLog("Supply Rate (scaled up by 1e18): ", supplyRateMantissa);
// 必须这样传参数
cToken.mint{value: msg.value}();
console.log("cToken cETH balance: ", cToken.balanceOf(address(this)));
emit DepositETH("Supply ETH amount: ", msg.value);
return true;
}
use hardhat test
describe("depositUSDC", function () {
it("Test mint usdc", async function () {
const { tradingAccount, USDCSigner, USDCContract } =
await loadFixture(deployFixture);
let transferApprove = await USDCContract.connect(
USDCSigner
).approve(
tradingAccount.address,
ethers.BigNumber.from("180000000")
);
let ret1 = await transferApprove.wait();
let transferTx = await USDCContract.connect(USDCSigner).transfer(
tradingAccount.address,
ethers.BigNumber.from("180000000")
);
let ret2 = await transferTx.wait();
console.log(ret1);
console.log(ret2);
let getBalance = await USDCContract.connect(USDCSigner).balanceOf(
tradingAccount.address
);
console.log("getBalance: ", getBalance);
let tx0 = await tradingAccount
.connect(USDCSigner)
.depositUSDC(ethers.BigNumber.from("180000000"));
let receipt = await tx0.wait();
// // 可以捕获到相对应的事件参数
// receipt.events?.filter((x) => {
// if (x.event == "DepositUSDC") {
// console.log(x.args);
// }
// });
});
});
Execute transaction tx0, check the hardhat node log, and find that the contract has not received the USDC of the previous transaction transfer.
enter image description here
enter image description here
But different things happened in the following test
function flashSwap(address _tokenBorrow, uint _amount) public {
uint256 beforeBalance = IERC20(USDC).balanceOf(address(this));
console.log("beforeBalance --- %d", beforeBalance);
address pair = IUniswapV2Factory(FACTORY).getPair(_tokenBorrow, USDC);
require(pair != address(0), "!pair");
address token0 = IUniswapV2Pair(pair).token0();
address token1 = IUniswapV2Pair(pair).token1();
// 借的如果是usdc, amount0Out就 > 0 == 借的如果是weth, amount1Out > 0
uint amount0Out = _tokenBorrow == token0 ? _amount : 0;
uint amount1Out = _tokenBorrow == token1 ? _amount : 0;
// need to pass some data to trigger uniswapV2Call
bytes memory data = abi.encode(_tokenBorrow, _amount);
IUniswapV2Pair(pair).swap(amount0Out, amount1Out, address(this), data);
if (amount0Out > 0) {
emit FlashSwapUSDC("flashswap usdc amount: ", amount0Out);
} else {
emit FlashSwapETH("flashswap WETH amount: ", amount1Out);
}
}
it("Test flashSwap borrow WETH", async function () {
const { tradingAccount, USDCContract, USDCSigner } =
await loadFixture(deployFixture);
let transferTx = await USDCContract.connect(USDCSigner).transfer(
tradingAccount.address,
ethers.BigNumber.from("180000000000")
);
await transferTx.wait();
let tx0 = await tradingAccount.flashSwap(
WETH,
ethers.utils.parseEther("1.5")
);
let receipt = await tx0.wait();
receipt.events?.filter((x) => {
if (x.event == "FlashSwapETH") {
console.log(x.args);
}
});
});
enter image description here
enter image description here
Can someone explain this reason to me?
Why is the result of the first test different from that of the first test

Get all transactions for an NFT on Solana

I want to collect all transactions for an NFT.
For example, you can display all transactions here:
https://explorer.solana.com/address/2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V
or here:
https://solscan.io/token/2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V#txs
But is there any way to do this with the API?
I checked
solana-py: https://michaelhly.github.io/solana-py/
and solscan api: https://public-api.solscan.io/docs/
But I could not find a way to do it.
You can use the getSignaturesForAddress RPC method on the mint address and walk backward to get all the transactions.
Here is an example in JS:
import {
Connection,
clusterApiUrl,
ConfirmedSignatureInfo,
PublicKey,
} from "#solana/web3.js";
const connection = new Connection(clusterApiUrl("mainnet-beta"));
export const getTxs = async (connection: Connection, pubkey: PublicKey) => {
const txs: ConfirmedSignatureInfo[] = [];
// Walk backward
let lastTransactions = await connection.getConfirmedSignaturesForAddress2(
pubkey
);
let before = lastTransactions[lastTransactions.length - 1].signature;
txs.push(...lastTransactions);
while (true) {
const newTransactions = await connection.getConfirmedSignaturesForAddress2(
pubkey,
{
before,
}
);
if (newTransactions.length === 0) break;
txs.push(...newTransactions);
before = newTransactions[newTransactions.length - 1].signature;
}
return txs;
};
getTxs(
connection,
new PublicKey("2Nzt8TYeAfgJDftKzkb7rgYShVvyXTR7cPVvpqaZ2a4V")
);
The equivalent method in Solana.py is this one https://michaelhly.github.io/solana-py/rpc/api/#solana.rpc.api.Client.get_signatures_for_address

Buy NFT from wallet1 which has all minted nft to the user wallet connected with phantom, Javascript, Solana

Here is my code to transfer nft from Alice Account (which has my all minted nfts) and feePayer account which will buy from the Alice Wallet. Well this works perfectly fine like this. But the problem is when the same transection I try to sign and send with phantom wallet it gives me an error (You can check it by the commented line 101 to 108) when I uncomment the phantom signAndSend method code and try to execute it, it gives me error RPC req rejected but the same is successfully done with the connection.sendTransaction.
That was problem 1,
Now problem 2 is that
In this case, I had used feePayer which had the keypair already, but if I want to make it as user connects with connectWallet button, ill had only publicKey of the user. Now in that situaion how can i make the the nft transfer from Alice wallet to the user who connected and clicked on buy?
JS Code:
const sendNft = async () => {
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"3DdVyZuANr5en2PQymCPmoFBMsfdhjaRHqnk3ejW*************************************************"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const alice = Keypair.fromSecretKey(
bs58.decode(
"2YQDdnfxiHPKu9GypLX1yXaQTQojvDSPgFkDxrU*************************************************"
)
);
const mintPubkey = new PublicKey(
"A8SJfwzKJAaMrY6Lb9FxZCfmVMVLcjKvRuzAiNiU6of5"
);
const getProvider = async () => {
if ("solana" in window) {
// opens wallet to connect to
await window.solana.connect();
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
window.open("https://www.phantom.app/", "_blank");
}
};
window.solana.on("connect", () => console.log("connected!"))
const network = "https://api.devnet.solana.com";
const connection = new Connection(network);
var prodivder = await getProvider();
console.log(prodivder.publicKey.toString())
var provider = await getProvider()
console.log(provider)
// calculate ATA
let accountAlice = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
alice.publicKey // owner
);
console.log(`ATA: ${accountAlice.toBase58()}`);
let tx3 = new Transaction().add(
Token.createAssociatedTokenAccountInstruction(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
accountAlice, // ata
alice.publicKey, // owner of token account
alice.publicKey // fee payer
)
);
// calculate ATA
let accountPayer = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
feePayer.publicKey // owner
);
console.log(`ATA: ${accountPayer.toBase58()}`);
let tx2 = new Transaction().add(
Token.createAssociatedTokenAccountInstruction(
ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
mintPubkey, // mint
accountPayer, // ata
feePayer.publicKey, // owner of token account
feePayer.publicKey // fee payer
)
);
// console.log(`txhash: ${await connection.sendTransaction(tx2, [feePayer])}`);
let tx = new Transaction().add(
Token.createTransferCheckedInstruction(
TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID
accountAlice, // from (should be a token account)
mintPubkey, // mint
accountPayer, // to (should be a token account)
alice.publicKey, // owner of from
[], // for multisig account, leave empty.
1, // amount, if your deciamls is 8, send 10^8 for 1 token
0 // decimals
)
);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Commenting out this, thus is the phantom codes
tx2.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
tx2.feePayer = feePayer.publicKey;
const { signature } = await window.solana.signAndSendTransaction(tx2);
await connection.confirmTransaction(signature);
// phantom code ends
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer, alice /* fee payer + owner */])}`);
};

keep getting transaction failed when trying to do pancake swap transactions in nodejs with web3 and ethersjs

error message (code attached below)
node_modules\#ethersproject\logger\lib\index.js:180
var error = new Error(message);
^
Error: transaction failed (transactionHash="0x03e0911d26d2175d55b233b4a7b17d06202e7c2fb52a2ecfd35f3863814cb374", transaction={"nonce":364,"gasPrice":{"type":"BigNumber","hex":"0x02540be400"},"gasLimit":{"type":"BigNumber","hex":"0x7a1200"},"to":"0x10ED43C718714eb63d5aA57B78B54704E256024E","value":{"type":"BigNumber","hex":"0x00"},"data":"0xa5be382e000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000003975383df42df8ed045d636b255bf0829d8d5970000000000000000000000000000000000000000000000000000000006698a9df0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c00000000000000000000000055d398326f99059ff775485246999027b3197955","chainId":56,"v":147,"r":"0xc1a926e6f3989a50185b2d75c4bc877a76c8a2f30d505a1055fa89271feba035","s":"0x0ebeb2da65954541c82ddf468177cc6a49324a0e7a6e3fb3f5795f41c1055261","from":"0x3975383Df42Df8ED045d636b255Bf0829d8D5970","hash":"0x03e0911d26d2175d55b233b4a7b17d06202e7c2fb52a2ecfd35f3863814cb374","type":null}, receipt={"to":"0x10ED43C718714eb63d5aA57B78B54704E256024E","from":"0x3975383Df42Df8ED045d636b255Bf0829d8D5970","contractAddress":null,"transactionIndex":19,"gasUsed":{"type":"BigNumber","hex":"0x5a67"},"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","blockHash":"0xd504dfc3e7703e7657239e04f0d36e8118633689395cfc6fb9b3d6f213893724","transactionHash":"0x03e0911d26d2175d55b233b4a7b17d06202e7c2fb52a2ecfd35f3863814cb374","logs":[],"blockNumber":7497373,"confirmations":1,"cumulativeGasUsed":{"type":"BigNumber","hex":"0x216ce6"},"status":0,"byzantium":true}, code=CALL_EXCEPTION, version=providers/5.1.2)
at Logger.makeError (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\logger\lib\index.js:180:21)
at Logger.throwError (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\logger\lib\index.js:189:20)
at JsonRpcProvider.<anonymous> (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\providers\lib\base-provider.js:1162:36)
at step (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\providers\lib\base-provider.js:48:23)
at Object.next (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\providers\lib\base-provider.js:29:53)
at fulfilled (D:\codeforFun\322-uniswap-trading-bot\node_modules\#ethersproject\providers\lib\base-provider.js:20:58)
at processTicksAndRejections (node:internal/process/task_queues:94:5) {
code, get from here
const ethers = require('ethers');
const {ChainId, Token, TokenAmount, Fetcher, Pair, Route, Trade, TradeType, Percent} =
require('#pancakeswap-libs/sdk');
const Web3 = require('web3');
const {JsonRpcProvider} = require("#ethersproject/providers");
require("dotenv").config();
const provider = new JsonRpcProvider('https://bsc-dataseed1.binance.org/');
const web3 = new Web3('wss://apis.ankr.com/wss/c40792ffe3514537be9fb4109b32d257/946dd909d324e5a6caa2b72ba75c5799/binance/full/main');
const { address: admin } = web3.eth.accounts.wallet.add(process.env.PRIVATE_KEY);
console.log(`Modulos cargados`);
// Command Line Input
const InputTokenAddr = web3.utils.toChecksumAddress(process.argv[2]);
// var BUSD = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56';
const OutputTokenAddr = web3.utils.toChecksumAddress(process.argv[3]);
// var WBNB = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
const InputTokenAmount = process.argv[4]
const Slipage = process.argv[5];
const PANCAKE_ROUTER = process.argv[6];
// const PANCAKE_ROUTER_V2 = '0x10ed43c718714eb63d5aa57b78b54704e256024e';
// const PANCAKE_ROUTER_V1 = '0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F';
// 1/1000 = 0.001
const ONE_ETH_IN_WEI = web3.utils.toBN(web3.utils.toWei('1'));//BN->(BIG NUMBER) || toWei -> Converts any ether value value into wei.
const tradeAmount = ONE_ETH_IN_WEI.div(web3.utils.toBN('1000'));//tradeAmount = ONE_ETH_IN_WEI/1000
console.log(`tradeAmount ` + tradeAmount );
const init = async () => {
const [INPUT_TOKEN, OUTPUT_TOKEN] = await Promise.all(
[InputTokenAddr, OutputTokenAddr].map(tokenAddress => (
new Token(
ChainId.MAINNET,
tokenAddress,
18
)
)));
console.log(` <<<<<------- pair-------->>>>>`);
const pair = await Fetcher.fetchPairData(INPUT_TOKEN, OUTPUT_TOKEN, provider);
//console.log(JSON.stringify(pair));
console.log(` <<<<<------- route-------->>>>>`);
const route = await new Route([pair], INPUT_TOKEN);
//console.log(JSON.stringify(route));
console.log(` <<<<<------- Trade-------->>>>>`);
const trade = await new Trade(route, new TokenAmount(INPUT_TOKEN, tradeAmount), TradeType.EXACT_INPUT);
//console.log(JSON.stringify(trade));
//https://uniswap.org/docs/v2/javascript-SDK/trading/
const slippageTolerance = new Percent(Slipage, '100'); //
console.log("slippageTolerance: " + JSON.stringify(slippageTolerance));
// create transaction parameters
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw;
const path = [INPUT_TOKEN.address, OUTPUT_TOKEN.address];
const to = admin;
const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
// Create signer
const wallet = new ethers.Wallet(
Buffer.from(
process.env.PRIVATE_KEY,
"hex"
)
);
const signer = wallet.connect(provider);
// Create Pancakeswap ethers Contract
const pancakeswap = new ethers.Contract(
PANCAKE_ROUTER,
['function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'],
signer
);
//Allow input token
if(true)
{
console.log(`Allow Pancakeswap <<<<<------- START-------->>>>>`);
let abi = ["function approve(address _spender, uint256 _value) public returns (bool success)"];
let contract = new ethers.Contract(INPUT_TOKEN.address, abi, signer);
let aproveResponse = await contract.approve(PANCAKE_ROUTER, ethers.utils.parseUnits('1000.0', 18), {gasLimit: 100000, gasPrice: 5e9});
console.log(JSON.stringify(aproveResponse));
console.log(`Allow Pancakeswap <<<<<------- END-------->>>>>`);
}
if(true)
{
console.log(`Ejecutando transaccion`);
var amountInParam = ethers.utils.parseUnits(InputTokenAmount, 18);
var amountOutMinParam = ethers.utils.parseUnits(web3.utils.fromWei(amountOutMin.toString()), 18);
console.log("amountInParam: " + amountInParam);
console.log("amountOutMinParam: " + amountOutMinParam);
console.log("amountOutMin: " + amountOutMin);
const tx = await pancakeswap.swapExactTokensForTokens(
amountInParam,
amountOutMinParam,
path,
to,
deadline,
{ gasLimit: ethers.utils.hexlify(300000), gasPrice: ethers.utils.parseUnits("9", "gwei") }
);
console.log(`Tx-hash: ${tx.hash}`)
const receipt = await tx.wait();
console.log(`Tx was mined in block: ${receipt.blockNumber}`);
}
}
init();

Web3 | TransferFrom() transactions always Failed

I'm trying to send Custom ERC20 Token to Owner Wallet Address using transferFrom() function using Web3.js
However all the Transactions are failed. Which is the same problem occur on Remix IDE.
Some answers on stackOverflow here says that the approve() is needed to call first before the transferFrom() function. so, I tried on Remix frist but I got the same problem. And then tried with using Web3.js like below.
const myContract = new web3.eth.Contract(abi);
const amount = sendAmount;
let address = myAddress;
myContract.options.address = contractAddress;
myContract.options.from = TokenOwner;
let options = myContract.options;
let data1 = myContract.methods.approve(address, amount).encodeABI();
let data2 = myContract.methods.transferFrom(address, TokenOwner, amount).encodeABI();
const ethAccount = fromPrivateKey(toBuffer("0x..."));
const fromPrivateKeyBuffer = ethAccount.getPrivateKey();
web3.eth.getTransactionCount(TokenOwner, (err, count) => {
if (err) return;
const txData = {
chainId: 0x03,
gasPrice: web3.utils.toHex(42000000000),
gasLimit: web3.utils.toHex(90000),
to: contractAddress,
from: TokenOwner,
value: 0x0,
nonce: web3.utils.toHex(count),
data: data1
};
const tx = new ethTx(txData);
tx.sign(fromPrivateKeyBuffer);
const serializedTx = tx.serialize().toString("hex");
if (!serializedTx) {
return;
} else {
web3.eth.sendSignedTransaction(`0x${serializedTx}`, (err, MuiTXHash) => {
console.log("err : ", err, "Data1-MuiTXHash : ", MuiTXHash);
// START DATA2
web3.eth.getTransactionCount(TokenOwner, (err, count) => {
if (err) return;
const txData2 = {
chainId: 0x03,
gasPrice: web3.utils.toHex(42000000000),
gasLimit: web3.utils.toHex(90000),
to: contarctAddress,
from: TokenOwner,
value: 0x0,
nonce: web3.utils.toHex(count + 1),
data: data2
};
const tx2 = new ethTx(txData2);
tx2.sign(fromPrivateKeyBuffer);
const serializedTx2 = tx2.serialize().toString("hex");
if (!serializedTx2) {
return;
} else {
web3.eth.sendSignedTransaction(`0x${serializedTx2}`, (err, MuiTXHash2) => {
console.log("err : ", err, "Data2-MuiTXHash : ", MuiTXHash2);
});
}
});
// END DATA2
});
}
});
};
I got the two Transaction Hash return data and the TransferFrom() transaction is failed again.
What is the problem?
How can I make it success? I have to withdraw the custom ERC20 token from specific address to owner. so I have to use transferFrom() transaction.
Please let me know how to do. Thanks.
I guess the compiling on Remix had some errors so I created new solidity file with same code on it and deployed it. The new smart contract worked well and no errors occurred. The errors was not about my code. If someone's suffering like this problems, then create a new contract address and I don't recommend using 'At Address' on Remix. This is not work properly at all.
I was tried appove() + transferFrom () , allowance() on Solidity working well but on web3 not working error same as you
I guess the transferFrom function should be called by the spender (i.e the address to which the TokenOwner has approved to spend). So,
const txData2 = {
chainId: 0x03,
gasPrice: web3.utils.toHex(42000000000),
gasLimit: web3.utils.toHex(90000),
to: contarctAddress,
from: address, // spender's address
value: 0x0,
nonce: web3.utils.toHex(count + 1),
data: data2
};
And don't forget to use spender's privateKey to sign the txn and spender's address in getTransactionCount
Read Here : Ethereum Wiki
Hope it helps. :)