How do I transfer ERC20 tokens using Ether.js? - ethereum

I'm trying to test my smart contract in Hardhat, but in order to do so I first need to send some ERC20 tokens to my contract (for this test I'm using USDC).
In my test I've impersonated a USDC whale, but how do I actually transfer the USDC to my contract?
it("USDC test", async function () {
const testContract =
await ethers.getContractFactory("TestContract")
.then(contract => contract.deploy());
await testContract.deployed();
// Impersonate USDC whale
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [USDC_WHALE_ADDRESS],
});
const usdcWhale = await ethers.provider.getSigner(USDC_WHALE_ADDRESS);
// Need to transfer USDC from usdcWhale to testContract
});

To transfer an ERC20 token you first need to deploy the token's main contract. You'll need the tokens contract address as well as the ERC20 ABI.
const USDC_ADDRESS = "0x6262998ced04146fa42253a5c0af90ca02dfd2a3";
const ERC20ABI = require('./ERC20ABI.json');
const provider = ethers.provider;
const USDC = new ethers.Contract(USDC_ADDRESS, ERC20ABI, provider);
Then to transfer 100 USDC from usdcWhale to testContract do:
await USDC.connect(usdcWhale).transfer(testContract.address, 100);

Related

How to send ETH to a contract function with ethers.js?

I am trying to send ETH to a contract function from a web app via metamask and ethers.js. So far I have tried:
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const splitterManager = new ethers.Contract(contract.address, contract.abi, signer);
var overrides = {value: 5}
const result = await splitterManager.newSplitter(addresses, shares, erc20, overrides);
console.log(result);
But I keep getting 'Error: resolver or addr is not configured for ENS name (argument="name", value="", code=INVALID_ARGUMENT, version=contracts/5.2.0)'.
You can call the contracts function and pass it an object containing a value key.
contractInstance.testFunction(<any function args>, { value: ethers.utils.parseUnits("1", "ether") });
This would call your contract's function and send that amount of wei to the contract.
function testFunction() public payable {
// contract code
}
If the contract has implemented the receive function, you can send ether to a contract same as sending ether to any other account. Here's a short example:
const accounts = await provider.listAccounts();
const signer = provider.getSigner(accounts[0]);
tx = {
to: **CONTRACT_ADDRESS**,
value: ethers.utils.parseEther('2', 'ether')
};
const transaction = await signer.sendTransaction(tx);
await contractInstance
.connect(rpcProvider)
.function({
value: ethers.utils.parseUnits("1","ether")
});
this should work
some address is an invalid address it could be the contract.address, the addresses, or some other address

How to pass an Interface object in a constructor parameter?

I don't know how to deploy this contract whit HARDHAT because there is an Interface object in the constructor.
Please can someone explain to me how to initialize IUniswapV2Pair _pair
IUniswapV2Pair is a Uniswap Library written in Solidity.
const Unitest = await hre.ethers.getContractFactory("Unitest");
const unitest = await Unitest.deploy(int256 .....,
uint256 .... , IUniswapV2Pair(?????));
await unitest.deployed();
console.log("unitest deployed to:", unitest.address);
You get the address of Interface. This is in rinkeby: https://rinkeby.etherscan.io/address/0x6bcd5b1e919277afe06a3f6355265ff3cf7956a4#code
and then when you deploy the contract,
const Uniswap = await hre.ethers.getContractFactory("ContractName");
const contract = await NFTMarket.deploy("0x6BcD5b1E919277AFe06a3f6355265ff3Cf7956A4",period,startTime);

Check balance of ERC20 token in Hardhat using Ethers.js

I'm writing unit tests using Hardhat's mainnet fork, and for a test I want to check the owner account's initial balance of an ERC20 token, in particular DAI. Here's my test so far:
const { ethers } = require("hardhat");
describe("Simple Test", function () {
it("Check balance of DAI", async function () {
const provider = ethers.provider;
const [owner] = await ethers.getSigners();
// Want to get initial DAI balance here so it can be compared later
});
});
What's a simple way to do this?
Found what I was looking for. First thing I did was save the DAI contract address at the top:
const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f";
Then I had to use the ERC20 token ABI, which I placed in the same folder as my test:
const ERC20ABI = require('./ERC20.json');
Then to get the owner account's DAI balance I just called balanceOf() from the DAI contract:
const DAI = new ethers.Contract(DAI_ADDRESS, ERC20ABI, provider);
DAIBalance = await DAI.balanceOf(owner.address);
This should work for any ERC20 token as well.

How to interact with the deployed ERC20(openzeppelin ERC20 contract) token and transfer token from user address X to address Y?

I've created a simple Contract extending openzeppelin ERC20.
I'm trying to transfer token from one address to another.
Contract code is as below:
File name: Token.sol
pragma solidity ^0.7.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
uint256 public INITIAL_SUPPLY = 100000;
constructor() ERC20("My Token", "MYT") {
_mint(msg.sender, INITIAL_SUPPLY);
}
}
Code within test file:
const { expect } = require("chai");
describe("Send token from second address in the block", function () {
it("Send 100 MYT to the third account", async function () {
const Token = await ethers.getContractFactory("Token");
const token = await Token.deploy();
// get accounts from the network
const [owner, secondAccount, thirdAccount] = await ethers.getSigners();
// send some credit to the second account
await token.transfer(secondAccount.address, 500);
// Approve token transfer
await token.approve(secondAccount.address, 200);
// Transfer credit from second account to the third account (This step is not working)
await token.transferFrom(secondAccount.address, thirdAccount.address, 100);
});
});
Error received:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds allowance'
at Token.sub (#openzeppelin/contracts/math/SafeMath.sol:171)
at Token.transferFrom (#openzeppelin/contracts/token/ERC20/ERC20.sol:154)
at processTicksAndRejections (internal/process/task_queues.js:94:5)
at runNextTicks (internal/process/task_queues.js:63:3)
at listOnTimeout (internal/timers.js:501:9)
at processTimers (internal/timers.js:475:7)
at EthModule._estimateGasAction (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:421:9)
at HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:105:18)
at EthersProviderWrapper.send (node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
Thank you for the help.
If you check Approve if erc20, the function arguments expect address _spender, uint256 _value as arguments. In your case you approved secondAccount to withdraw 200 tokens.
It means secondAccount can transfer those token to his account from the token contract. To do that, you try await token.connect(secondAccount).transferFrom(token.address,secondAccount.address,100);

Using local private key with Web3.js

How can I interact with smart contracts and send transactions with Web3.js by having a local private key? The private key is either hardcoded or comes from an environment (.env) file?
This is needed for Node.js and server-side interaction or batch jobs with Ethereum/Polygon/Binance Smart Chain smart contracts.
You may encounter e.g. the error
Error: The method eth_sendTransaction does not exist/is not available
Ethereum node providers like Infura, QuikNode and others require you to sign outgoing transactions locally before you broadcast them through their node.
Web3.js does not have this function built-in. You need to use #truffle/hdwallet-provider package as a middleware for your Ethereum provider.
Example in TypeScript:
const Web3 = require('web3');
const HDWalletProvider = require("#truffle/hdwallet-provider");
import { abi } from "../../build/contracts/AnythingTruffleCompiled.json";
//
// Project secrets are hardcoded here
// - do not do this in real life
//
// No 0x prefix
const myPrivateKeyHex = "123123123";
const infuraProjectId = "123123123";
const provider = new Web3.providers.HttpProvider(`https://mainnet.infura.io/v3/${infuraProjectId}`);
// Create web3.js middleware that signs transactions locally
const localKeyProvider = new HDWalletProvider({
privateKeys: [myPrivateKeyHex],
providerOrUrl: provider,
});
const web3 = new Web3(localKeyProvider);
const myAccount = web3.eth.accounts.privateKeyToAccount(myPrivateKeyHex);
// Interact with existing, already deployed, smart contract on Ethereum mainnet
const address = '0x123123123123123123';
const myContract = new web3.eth.Contract(abi as any, address);
// Some example calls how to read data from the smart contract
const currentDuration = await myContract.methods.stakingTime().call();
const currentAmount = await myContract.methods.stakingAmount().call();
console.log('Transaction signer account is', myAccount.address, ', smart contract is', address);
console.log('Starting transaction now');
// Approve this balance to be used for the token swap
const receipt = await myContract.methods.myMethod(1, 2).send({ from: myAccount.address });
console.log('TX receipt', receipt);
You need to also avoid to commit your private key to any Github repository. A dotenv package is a low entry solution for secrets management.
You can achieve what you want by using ethers.js instead of web3 with no other package needed.
First import the library:
Node.js:
npm install --save ethers
const { ethers } = require("ethers");
Web browser:
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"
type="application/javascript"></script>
Define the provider. One way is using the provider URL like this:
const provider = new ethers.providers.JsonRpcProvider(rpcProvider);
Then, in order to interact with the contract without asking for authorization, we will create a wallet using the private key and the provider like this:
const signer = new ethers.Wallet(privateKey,provider)
Now, you can create the contract with the address, ABI, and the signer we created in the previous step:
const contract = new ethers.Contract(contractAddress,ABI, signer);
Now, you can interact with the contract directly. For example, getting the balance of a token:
const tokenBalance = await nftContractReadonly.balanceOf(signer.getAddress(),tokenId);
Don't forget to store the private key in a safe place and never hardcode it in a web page.
Further reading: Provider Signer
There is a better and simple way to sign and execute the smart contract function. Here your function is addBonus.
First of all we'll create the smart contract instance:
const createInstance = () => {
const bscProvider = new Web3(
new Web3.providers.HttpProvider(config.get('bscRpcURL')),
);
const web3BSC = new Web3(bscProvider);
const transactionContractInstance = new web3BSC.eth.Contract(
transactionSmartContractABI,
transactionSmartContractAddress,
);
return { web3BSC, transactionContractInstance };
};
Now we'll create a new function to sign and execute out addBonus Function
const updateSmartContract = async (//parameters you need) => {
try {
const contractInstance = createInstance();
// need to calculate gas fees for the addBonus
const gasFees =
await contractInstance.transactionContractInstance.methods
.addBonus(
// all the parameters
)
.estimateGas({ from: publicAddress_of_your_desired_wallet });
const tx = {
// this is the address responsible for this transaction
from: chainpalsPlatformAddress,
// target address, this could be a smart contract address
to: transactionSmartContractAddress,
// gas fees for the transaction
gas: gasFees,
// this encodes the ABI of the method and the arguments
data: await contractInstance.transactionContractInstance.methods
.addBonus(
// all the parameters
)
.encodeABI(),
};
// sign the transaction with a private key. It'll return messageHash, v, r, s, rawTransaction, transactionHash
const signPromise =
await contractInstance.web3BSC.eth.accounts.signTransaction(
tx,
config.get('WALLET_PRIVATE_KEY'),
);
// the rawTransaction here is already serialized so you don't need to serialize it again
// Send the signed txn
const sendTxn =
await contractInstance.web3BSC.eth.sendSignedTransaction(
signPromise.rawTransaction,
);
return Promise.resolve(sendTxn);
} catch(error) {
throw error;
}
}