'ERC20: insufficient allowance' when staking - solidity

Deployed an ERC20, that is set as an asset for separate staking contract (vault).
I was able to mint, transfer and increase allowance in the ERC20, but when trying to use the 'stake/deposit' function - this return:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: insufficient allowance'
The address is set as spender + owner, and on-chain calls verified the spender is aprroved under the ERC20.
Any ideas? I suspect it's related to proxy/contract routing.
Tried to stake ERC20 into a staking contract, received 'Allowance insufficient' error.

by any chance did you call the approve function on your ERC20 contract to approve the staking contract?
If you did, try to check your allowance again to the staking contract whether it is above the amount that you would like to stake. If the allowance to the staking contract is 0, then it will fail as you essentially have not give any permission from the staking contract to take your ERC20 token fro staking.
To check the token allowance to your staking contract, you can do so by using Moralis
import Moralis from 'moralis';
import { EvmChain } from '#moralisweb3/evm-utils';
try {
const chain = EvmChain.ETHEREUM;
const address = '';
const ownerAddress = '';
const spenderAddress = ''
await Moralis.start({
apiKey: 'YOUR_API_KEY',
// ...and any other configuration
});
const response = await Moralis.EvmApi.token.getTokenAllowance({
address,
chain,
});
console.log(response?.result);
} catch (e) {
console.error(e);
}
where the parameters are:
address is your ERC20 token address
chain is what chain your ERC20 token on
ownerAddress is the address that would like to stake the ERC20 token
spenderAddress is the staking contract
You can follow this tutorial further for more details https://docs.moralis.io/web3-data-api/evm/how-to-get-the-spender-allowance
Hope this helps!

Related

Get deployed contract by address

According to this doc. We can use ethers.getContract to get deployed contract.
I have deployed my contract at 0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2 and my creator address is 0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385 now to get contract i am doing
deployedContract = await ethers.getContract(
"0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2",
"0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385"
)
But its throwing error
Error: No Contract deployed with name 0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2
But you can see contract is deployed https://goerli.etherscan.io/address/0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2
Can someone help me here?
It's just simple.
You can use getContractAt function.
getContractAt: <T extends ethers.Contract>(
nameOrAbi: string | any[],
address: string,
signer?: ethers.Signer | string
) => Promise<T>;
So in your case, it could be:
const raffle = await ethers.getcontractAt(
"Raffle",
"0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2",
"0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385"
);
In addition, you got the error since you used the contract address for the contract name.
getContract: <T extends ethers.Contract>(
name: string,
signer?: ethers.Signer | string
) => Promise<T>;
The 0x33F4... contract is deployed on the Goerli testnet, and it's available only on this network. Your post doesn't state to which network is your ethers provider connected to, but based on the context I'm assuming it's a different network - for example the local emulated hardhat network (which is the default option if you don't specify any provider) or the Ethereum mainnet.
The getContract() function is present only in historic versions of the ethers package. Based on the documentation that you linked, it seems that you're using version 0.0.1 (and it seems that it's not a misconfiguration of the docs page, as the 0.0.1 version in fact exists). Current version (January 2023) of the package is 5.4 - you can find its docs at https://docs.ethers.io/v5/.
Second argument in the originally linked documentation is contractInterface. Which is not the deployer address (passed in your example) but an ABI (Application Binary Interface) - a JSON-formatted specification of public and external methods of the contract and its events. Example of such ABI JSON can be found in the original docs a below the Example headline.
Each contract usually has its own unique ABI that is generated from its source code during contract compilation, but you can also use generic ABI for standardized functions. For example all ERC-20 token contracts have the same functions required by the ERC-20 standard (and these functions are included in the generic ERC-20 ABI), plus they might implement some other functions on top of that (these custom functions are not in the generic ABI).
Here's an example of interacting with the contract with the current version (0.5.4) of ethers, connected to a Goerli network provider:
const { ethers } = require("ethers");
// A 3rd party provider that is connected to the Goerli network
const provider = new ethers.providers.JsonRpcProvider("https://goerli.infura.io/v3/<your_api_key>");
const CONTRACT_ADDRESS = "0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2";
// ABI JSON of this specific contract, not included in the answer for readability
const CONTRACT_ABI = [/* ... */];
async function run() {
const myContract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
// `getEntryFee()` function defined in the ABI JSON as well as in the actual contract
const entryFee = await myContract.getEntryFee();
console.log(entryFee.toString());
}
run();
Note: Above is a standalone NodeJS script that is not using the Hardhat framework. You can also add the network in your Hardhat config file, and then run a script from their scripts folder that automatically includes ethers and connects to the selected provider.
require("#nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.17",
networks: {
goerli: {
url: "https://goerli.infura.io/v3/<your_api_key>",
accounts: [<private_key>, <private_key>], // for sending transactions
}
}
};
npx hardhat run --network goerli scripts/myScript.js
Add this to hardhat.config.js
networks: {
goerli: {
url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
accounts: [process.env.PRI_KEY],
},
},
create .env and add your env variables
// I am loading env variables
env $(cat .env) npx hardhat run --network goerli scripts/yourScriptFile.js

How to aggregate multiple smart contract function calls on Rootstock?

I have multiple ERC20 tokens, deployed on Rootstock,
and I want to track their balances and allowances in a real time from my DApp.
In ethers.js,
I can track their balances by alternately calling the functions
balanceOf(address) and allowance(owner, spender).
However, across two tokens, that equates to about
4 JSON-RPC requests every ~30 seconds.
I would prefer to reduce the frequency of JSON-RPC requests made by my application,
by aggregating these particular requests.
Is it possible to combine multiple smart contract data queries
into a single JSON-RPC request via ethers.js or any other library?
You could take a look at #0xsequence/multicall. It consists of:
MultiCallUtils smart contract with a multiCall() function intended for making aggregated calls
JS frontend library which includes a Multicall wrapper around ethers.js provider.
Smart contract deployments:
MultiCallUtils is deployed on the Rootstock Testnet: 0xb39d1Dea1bF91Aef02484F677925904b9d6936B4
I am not sure whether it is deployed at Rootstock Mainnet or not, anyway, you can deploy it there yourself.
To make aggregated smart contract calls:
Install the npm package:
npm i #0xsequence/multicall
Import the library to your project:
const { providers } = require('#0xsequence/multicall');
Create a Rootstock Testnet configuration:
const multicallConfig = {
// RSK Testnet
31: {
// maximum number of calls to batch into a single JSON-RPC call
batchSize: 50,
// defines the time each call is held on buffer waiting for subsequent calls before aggregation, ms
timeWindow: 50,
// MultiCallUtils smart contract
contract: '0xb39d1Dea1bF91Aef02484F677925904b9d6936B4',
},
};
Wrap your ethers.js current provider with a Multicall provider:
const multicallProvider = new providers.MulticallProvider(ethersProvider, multicallConfig[31]);
Connect your token smart contracts to the Multicall provider instead of ethers.js provider to be to able make aggregated calls:
const token1 = new ethers.Contract(
token1Address,
token1ABI,
multicallProvider,
);
const token2 = ...
Now you are ready to create an aggregated call:
function makeAggregatedCall() {
const aggregatedCall = [
multicallProvider.getBalance(address),
token1.balanceOf(address),
token1.allowance(owner, spender),
token2.balanceOf(address),
token2.allowance(owner, spender),
];
[
rbtcBalance,
balance1,
allowance1,
balance2,
allowance2,
] = await Promise.all(aggregatedCall);
}
The library will attempt to send all these function calls within a single call to MultiCallUtils smart contract multiCall() function.
However if the aggregated call fails,
as a fallback,
its constituent functions calls will be called individually via the ethers.js provider.
In order to subscribe to every newly minted block, attach the makeAggregatedCall function to the ethers provider block event listener:
ethersProvider.on('block', makeAggregatedCall);
You could use the ethereum-multicall project,
which consists of:
Frontend library which connects to
Multicall3 smart contract
Smart contract deployments:
The advantage of this project is that both Rootstock Mainnet and Rootstock Testnet have the Multicall3 deployments:
Mainnet 0xcA11bde05977b3631167028862bE2a173976CA11
Testnet 0xcA11bde05977b3631167028862bE2a173976CA11
... and bonus points for the 0xca11...ca11 vanity address ;)
To make aggregated smart contract calls:
Install the npm package:
npm i ethereum-multicall
Import the library to your project:
const { Multicall } = require('ethereum-multicall');
Create Multicall instance and connect it to ethers.js provider
const multicall = new Multicall({
ethersProvider: ethersProvider,
tryAggregate: true,
});
Create aggregated call:
const aggregatedCall = [
{
reference: 'token1',
contractAddress: token1Address,
abi: token1ABI,
calls: [
{
methodName: 'balanceOf',
methodParameters: [walletAddress],
},
{
methodName: 'allowance',
methodParameters: [ownerAddress, spenderAddress],
},
],
},
{
reference: 'token2',
contractAddress: token2Address,
abi: token2ABI,
calls: [
{
methodName: 'balanceOf',
methodParameters: [walletAddress],
},
{
methodName: 'allowance',
methodParameters: [ownerAddress, spenderAddress],
},
],
},
];
const { results } = await multicall.call(aggregatedCall);
Extract the required data from the results object

Ethers.js Contract call works from Brave browser but fails from Metamask Goerli Testnet

Contract - 0xaB9d2D124E70Be7039d7CCba9AFd06AdC1Bc60C0
All the failed transactions are called from Metamask, and all the successes are called from the Brave browser.
It's a basic, "update a contract property" call, nothing crazy.
It has always worked from Brave Browser, but I was getting Error: cannot estimate gas; transaction errors from Chrom/MetaMask, so I added the provider.getGasPrice()
async function SendMessage() {
contract = new ethers.Contract(contractAddress, abi, wallet);
let gasEst = await provider.getGasPrice();
console.log(ethers.utils.formatUnits(gasEst, 'gwei'));
return contract.SendRequest(message, { gasLimit: 1000000, gasPrice: gasEst });
}
Any help would be appreciated, thanks!
There is no contract on the 0xaB9d2D... address on the Ethereum mainnet (Etherscan link). So when you send it a transaction on the mainnet, it's a simple transfer between two end user addresses (in your case, you're sending value of 0 ETH) and the data field is ignored.
However, on the Goerli testnet (Etherscan link), there is a contract deployed on this address. Assuming this contract doesn't implement the SendRequest() function, nor the fallback() special function, it rejects all incoming transfers that are trying to execute a function that is not defined in this contract (in your case SendRequest()).

How to deploy a pre-compiled contract to hardhat node

I have a proxy contract and would like to replace the underlying implementation contract.
I already have the abi & bytecode of a smart contract(retrieved from artifacts folder), so here is what I did:
const NFTv2 = await ethers.getContractFactory(upgradedContract.abi, upgradedContract.bytecode);
contract = await upgrades.upgradeProxy(proxyContract.address, NFTv2);
It works fine, but I don't want the contract to exist in my contracts folder, so I've deleted it and run npx hardhat compile again.
Now when I try to run this deploy script again, hardhat keep throwing this error:
Error: The requested contract was not found. Make sure the source code is available for compilation
at getContractNameAndRunValidation (node_modules/#openzeppelin/upgrades-core/src/validate/query.ts:46:11)
at Object.getStorageLayout (node_modules/#openzeppelin/upgrades-core/src/validate/query.ts:54:41)
at Object.deployImpl (node_modules/#openzeppelin/hardhat-upgrades/src/utils/deploy-impl.ts:30:18)
at Proxy.upgradeProxy (node_modules/#openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:36:22)
After some try & error, it seems to be related to the cache folder, once the related metadata inside the cache folder disappeared, then this error will pop out, otherwise no.
Can someone guide me on this problem and how can I deploy contract with only abi & bytecode without leaving the contract inside the contracts folder?
Thank you! :)
Here's the code of my upgraded contract:
// SPDX-License-Identifier: Apache2.0
pragma solidity ^0.8.4;
import "#openzeppelin/contracts-upgradeable/token/ERC1155/presets/ERC1155PresetMinterPauserUpgradeable.sol";
contract Test is ERC1155PresetMinterPauserUpgradeable {
string private _uri;
event upgradeEvent(string);
function uri(uint256) public view virtual override returns (string memory) {
return string(abi.encodePacked(_uri, "/new"));
}
function seturi(string memory uri) public {
emit upgradeEvent("this is an upgraded contract");
_uri = uri;
}
}
I stumbled upon this question because I struggled with the same issue, but here is what I did in the end. Basic idea is to ignore the API extensions provided by Hardhat and use Ethers.js directly.
const allSigners = await hre.ethers.getSigners();
const deployingSigner = allSigners[0];
const factory = new ContractFactory(artifact.abi, artifact.bytecode, deployingSigner);
const contract = await factory.deploy(); // no args
await contract.deployed();
console.log("Contract deployed to: ", contract.address);

Cannot able to call the contract inside the truffle console

I am new to the truffle framework. I have initialised my contract Dapp with the constructor function as given below
pragma solidity ^0.5.0;
contract Dapp {
uint public totalSupply;
constructor() public {
totalSupply = 1000000;
}
}
and my migrations file in regards with the contract is
const Dapp = artifacts.require("Dapp");
module.exports = function(deployer) {
deployer.deploy(Dapp);
};
I have compiled and migrated using the command truffle compile and truffle migrate, which results in successful compilation.
But when accessing the contract in truffle console like
let instance = await Dapp.deployed()
It results in ReferenceError: Dapp is not defined, I cannot able to figure out what went wrong. Is there any possible solution to this. And yeah I have followed the latest Truffle documentation. And also, I have followed the solution been presented in this platform.
Documentation link for migration and interacting with truffle console.