Balancer flashloan transaction execution reverting on Polygon Mumbai Testnet - ethereum

I'm trying to call the flashLoan() function on Balancer's vault contract but I keep getting an 'execution reverted' error when I view the transaction on polygonscan mumbai.
Here's my smart contract code:
// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.8.7;
pragma abicoder v2;
import "#balancer-labs/v2-interfaces/contracts/vault/IFlashLoanRecipient.sol";
import "#openzeppelin/contracts/utils/math/SafeMath.sol";
interface Vault {
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
}
contract FlashLoanSimple is IFlashLoanRecipient {
using SafeMath for uint256;
address internal constant vaultAddr = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
Vault vault = Vault(vaultAddr);
function receiveFlashLoan(IERC20[] memory tokens,uint256[] memory amounts,uint256[] memory
feeAmounts,bytes memory userData) external override {
userData;
for (uint i = 0; i < tokens.length; i++) {
uint amountOwing = amounts[i].add(feeAmounts[i]);
if(address(this).balance >= amountOwing) {
IERC20(tokens[i]).approve(vaultAddr,amountOwing);
IERC20(tokens[i]).transfer(vaultAddr, amountOwing);
}
}
}
function executeFlashLoan(address _flTokenAddr,uint256 _flAmount) external {
IERC20 flToken = IERC20(_flTokenAddr);
IERC20[] memory flTokens = new IERC20[](1);
uint256[] memory flAmounts = new uint256[](1);
flTokens[0] = flToken;
flAmounts[0] = _flAmount ;
Vault(vaultAddr).flashLoan(IFlashLoanRecipient(address(this)),flTokens,flAmounts,"");
}
}
and here is part of my script:
const maticProvider = new ethers.providers.JsonRpcProvider("https://polygon-
mumbai.g.alchemy.com/v2/Q0iw05Ps4B9YV10FMtVUSBOzxNKVoV2x");
const private_key = "xxxxxxxxxxxxxxxxxxxxxxxx";
const signer = new ethers.Wallet(private_key, maticProvider);
const Flashloan = new ethers.Contract(flashloanAddress,FlashloanJson.abi,maticProvider);
export const flashloan = async (address: string, amountIn: BigNumber) => {
const gasPrice = await maticProvider.getGasPrice();
const tx = await Flashloan.connect(signer).executeFlashLoan(address,amountIn, {gasLimit:
15000000,gasPrice: gasPrice});
return tx;
};
Any help would be greatly appreciated, I was getting an error related to gas before, but I'm no longer getting that error after I increased the gas limit. My contract is deployed on the Polygon Mumbai network and has a balance of 3 MATIC.

The problem was that I was using the Mumbai network, it only works when deployed on the mainnet.

Related

My Solidity program work on Ganache but not on testnet (Goerli)

I want to get all reserve in UniswapV2 pool in one request to the EVM. Here is the code getReserve :
// SPDX-License-Identifier: MIT
// compiled with 0.8.17
pragma solidity >=0.4.22 <0.9.0;
contract IUniswapV2Pair {
function getReserves() public view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) {}
}
contract getReserve {
function get(address[] memory _add) external view returns (uint[] memory) {
uint n = _add.length;
uint[] memory liste = new uint[](n*2);
// Define variables to store the returned values
uint112 reserve0;
uint112 reserve1;
uint32 blockTimestampLast;
for (uint i=0; i<n; i++) {
// Call the getReserves function in the other contract and store the returned values
(reserve0, reserve1, blockTimestampLast) = IUniswapV2Pair(_add[i]).getReserves();
liste[i*2] = reserve0;
liste[i*2+1] = reserve1;
}
return liste;
}
function getOnlyOne(address _add) external view returns (uint112, uint112, uint32) {
return IUniswapV2Pair(_add).getReserves();
}
}
To test that this program work well on my Ganache EVM I have created this program IUniswapV2Pair:
// SPDX-License-Identifier: MIT
// compiled with 0.8.17
pragma solidity >=0.4.22 <0.9.0;
contract IUniswapV2Pair {
function getReserves() external pure returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) {
reserve0 = 11;
reserve1 = 12;
blockTimestampLast = 13;
return (reserve0, reserve1, blockTimestampLast);
}
}
Like I said, it is working well on my Ganache EVM. But when I deploy it on the GOERLI testnet it is not working, here is the addresss :
getReserve : 0x993305D7d90675656857c7Cd69f1CF57242D79D5
IUniswapV2Pair : 0x33e57A530F90aB2A5572E2a877161Ca644e8FC95
My Problem is to make getOnlyOne("0x33e57A530F90aB2A5572E2a877161Ca644e8FC95") working.
1 Testing code on Goerli
I have tried to connect to GOERLI via Python, here is the code :
from web3 import Web3
import json, web3
server = "https://eth-goerli.public.blastapi.io"
w3 = Web3(Web3.HTTPProvider(server))
w3.isConnected()
# Contrat intermédiaire
address = "0x993305D7d90675656857c7Cd69f1CF57242D79D5"
abi = [{"inputs":[{"internalType":"address[]","name":"_add","type":"address[]"}],"name":"get","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function","constant":true},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getOnlyOne","outputs":[{"internalType":"uint112","name":"","type":"uint112"},{"internalType":"uint112","name":"","type":"uint112"},{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function","constant":true}]
contract = w3.eth.contract(address=address, abi=abi)
contract.all_functions()
contract.functions.get(["0x33e57A530F90aB2A5572E2a877161Ca644e8FC95"]).call()
contract.functions.getOnlyOne("0x33e57A530F90aB2A5572E2a877161Ca644e8FC95").call()
I have this error web3.exceptions.ContractLogicError: execution reverted, which I don't have when I do it on Ganache.
And to make sure that it is not a problem from IUniswapV2Pair I have this code:
address = "0x33e57A530F90aB2A5572E2a877161Ca644e8FC95"
abi = [{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"reserve0","type":"uint112"},{"internalType":"uint112","name":"reserve1","type":"uint112"},{"internalType":"uint32","name":"blockTimestampLast","type":"uint32"}],"stateMutability":"pure","type":"function","constant":true}]
contract = w3.eth.contract(address=address, abi=abi)
contract.all_functions()
contract.functions.getReserves().call()
Which return me : [11, 12, 13]
2 Testing connection between contracts
I have created 2 others easier smart contract which have been working well here it is :
// SPDX-License-Identifier: MIT
// compiled with 0.8.17
pragma solidity >=0.4.22 <0.9.0;
contract FavoriteNumber {
uint favoriteNumber;
function getFavoriteNumber() external view returns(uint) {
return favoriteNumber;
}
function setFavoriteNumber(uint _favoriteNumber) external {
favoriteNumber = _favoriteNumber;
}
}
// SPDX-License-Identifier: MIT
// compiled with 0.8.17
pragma solidity >=0.4.22 <0.9.0;
contract FavoriteNumber {
function getFavoriteNumber() public view returns(uint) {}
function setFavoriteNumber(uint _favoriteNumber) public {}
}
contract ExistingNoSet {
function getA(address _t) public view returns (uint result) {
return FavoriteNumber(_t).getFavoriteNumber();
}
function setA(address _t, uint _val) public {
FavoriteNumber(_t).setFavoriteNumber(_val);
}
}
Here is the address :
FavoriteNumber : 0x14c89b4F462C11961Bb48aD6B2008f64617CF62a
ExistingNoSet : 0x97BdDaff1a971580f99C1DB850dE5EcF4982251a
And to test the code, here is the Python program, be careful I give a private key here (don't use it outside of a testnet) :
from web3 import Web3
import json, web3
server = "https://eth-goerli.public.blastapi.io"
private_key = "df49b58fbc863c5e60fe4e64829a853c46a8a12c3310404bc2a03bfefb89f68a"
public_add = "0xb4311ad11530F735ecE2d652Cbd56D1FB8D6Efeb"
w3 = Web3(Web3.HTTPProvider(server))
w3.isConnected()
# Contrat intermédiaire
address = "0x97BdDaff1a971580f99C1DB850dE5EcF4982251a"
abi = [{"inputs":[{"internalType":"address","name":"_t","type":"address"}],"name":"getA","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function","constant":true},{"inputs":[{"internalType":"address","name":"_t","type":"address"},{"internalType":"uint256","name":"_val","type":"uint256"}],"name":"setA","outputs":[],"stateMutability":"nonpayable","type":"function"}]
contract = w3.eth.contract(address=address, abi=abi)
contract.all_functions()
contract.functions.getA("0x14c89b4F462C11961Bb48aD6B2008f64617CF62a").call() # It should return 15
txn = contract.functions.setA(
"0x14c89b4F462C11961Bb48aD6B2008f64617CF62a", 3 # You set this new number
).build_transaction({
'nonce': w3.eth.get_transaction_count(public_add),
'gas': 200000,
'gasPrice': w3.toWei('20', 'gwei')
})
signed_txn = w3.eth.account.sign_transaction(txn, private_key=private_key)
w3.eth.send_raw_transaction(signed_txn.rawTransaction)
# You have to time sleep a little bit like 1min
contract.functions.getA("0x14c89b4F462C11961Bb48aD6B2008f64617CF62a").call() # It should return 3
So this program works well.
Thank you very to have read my post until here, I hope you will be able to help me.

"Execution reverted" error when I call createCollectible function on goerli testnet

I'm new to smart contract and Solidity programming and I've been trying to deploy an NFT contract on goerli testnet. The contract deploys without any problem but when I try to call the "createCollectible" function, I get the following error:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted
{
"originalError": {
"code": 3,
"data": "0xf0019fe60000000000000000000000000000000000000000000000000000000000000c6a000000000000000000000000b54644506388a04187d943dbbbd3edbb3ee53094",
"message": "execution reverted"
}
}
Here is my contract:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "#chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
import "#chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
/**
* #title The AdvandedCollectible contract
* #notice A contract that mints an NFT
*/
contract AdvancedCollectible is ERC721, VRFConsumerBaseV2 {
VRFCoordinatorV2Interface immutable COORDINATOR;
LinkTokenInterface immutable LINKTOKEN;
uint256 public tokenCounter;
uint64 immutable s_subscriptionId;
// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
bytes32 immutable s_keyhash;
uint32 immutable s_numWords = 1;
uint16 immutable s_requestConfirmations = 3;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Storing each word costs about 20,000 gas,
// so 100,000 is a safe default for this example contract. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 immutable s_callbackGasLimit = 100000;
uint256 public s_requestId;
uint256 public s_randomWords;
address s_owner;
enum Breed {
PUG,
SHIBA_INU,
ST_BERNARD
}
mapping(uint256 => Breed) public tokenIdToBreed;
mapping(uint256 => address) public requestIdToSender;
event requestCollectible(uint256 indexed requestId, address requester);
event breedAssigned(uint256 tokenId, Breed breed);
constructor(
address vrfCoordinator,
address link,
bytes32 keyhash,
uint64 subscriptionId
) VRFConsumerBaseV2(vrfCoordinator) ERC721("Dogie", "DOG") {
tokenCounter = 0;
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
LINKTOKEN = LinkTokenInterface(link);
s_keyhash = keyhash;
s_owner = msg.sender;
s_subscriptionId = subscriptionId;
}
modifier onlyOwner() {
require(msg.sender == s_owner, "You are not the owner");
_;
}
function createCollectible() public returns (uint256) {
s_requestId = COORDINATOR.requestRandomWords(
s_keyhash,
s_subscriptionId,
s_requestConfirmations,
s_callbackGasLimit,
s_numWords
);
requestIdToSender[s_requestId] = msg.sender;
emit requestCollectible(s_requestId, msg.sender);
}
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
internal
override
{
s_randomWords = randomWords[0];
Breed breed = Breed(s_randomWords % 3);
uint256 newTokenId = tokenCounter;
tokenIdToBreed[newTokenId] = breed;
emit breedAssigned(newTokenId, breed);
address owner = requestIdToSender[requestId];
_safeMint(owner, newTokenId);
tokenCounter++;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
require(
_isApprovedOrOwner(_msgSender(), tokenId),
"ERC721: Caller is not owner nor approved."
);
setTokenURI(tokenId, _tokenURI);
}
}
Does anybody have an idea what I'm doing wrong here?
So I realized that I'm missing one small yet important step, and that is adding a consumer to my subscription.
Using the Chainlink VRF V2, you need to create a subscription, add funds to that subscription and add the address where your contract is deployed at as a consumer to the subscription. I wasn't doing that last step and that's why my transaction's execution kept reverting.

Solidity function implementing `public onlyOwner` cannot be called even by the owner

I am following along the documentation here: https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft/how-to-mint-a-nft. And have a smart contract of form:
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract NFTA is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter public _tokenIds;
mapping (uint256 => string) public _tokenURIs;
mapping(string => uint8) public hashes;
constructor() public ERC721("NFTA", "NFT") {}
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
/**
* #dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
}
When I attempt to estimate the gas cost of minting with this:
const MY_PUBLIC_KEY = '..'
const MY_PRIVATE_KEY = '..'
const ALCHEMY = {
http: '',
websocket:'',
}
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const web3 = createAlchemyWeb3(ALCHEMY.http);
const NFTA = require("../artifacts/contracts/OpenSea.sol/NFTA.json");
const address_a = '0x...';
const nft_A = new web3.eth.Contract(NFTA.abi, address_a);
async function mint({ tokenURI, run }){
const nonce = await web3.eth.getTransactionCount(MY_PUBLIC_KEY, 'latest');
const fn = nft_A.methods.mintNFT(MY_PUBLIC_KEY, '')
console.log( 'fn: ', fn.estimateGas() )
}
mint({ tokenURI: '', run: true })
I receive error:
(node:29262) UnhandledPromiseRejectionWarning: Error: Returned error: execution reverted: Ownable: caller is not the owner
Presumably because mintNFT is public onlyOwner. However, when I check Etherscan, the From field is the same as MY_PUBLIC_KEY, and I'm not sure what else can be done to sign the transaction as from MY_PUBLIC_KEY. The easy way to solve this is to remove the onlyOwner from function mintNFT, and everything runs as expected. But suppose we want to keep onlyOwner, how would I sign the transaction beyond what is already written above.
Note I'm using hardHat to compile the contracts and deploying them. That is:
npx hardhat compile
npx hardhat run scripts/deploy.js
=============================================
addendum
The exact code given by alchemy to deploy the mint is:
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
};
Note in the transaction the from field is PUBLIC_KEY, the same PUBLIC_KEY that deployed the contract, and in this case the nftContract has public onlyOwner specified. This is exactly what I have done. So conceptually who owns this NFT code? On etherscan is it the to address ( the contract address ), or the from address, which is my public key, the address that deployed the contract, and the one that is calling mint, which is now failing with caller is not the owner error.
Search the internet, I see others have encountered this problem here: https://ethereum.stackexchange.com/questions/94114/erc721-testing-transferfrom, for Truffle you can specify the caller with extra field:
await nft.transferFrom(accounts[0], accounts[1], 1, { from: accounts[1] })
Extra parameters is not an option here because I'm using hardhat.
OpenZeppelin's Ownable.sol defines the default owner value as the contract deployer. You can later change it by calling transferOwnership() or renounce the owner (i.e. set to 0x0) by calling renounceOwnership().
The onlyOwner modifier reverts the transaction if it's not sent by the current owner. (see the code)
So you need to call the mintNFT() function from the same address that deployed the contract, because that's the current owner. Or you can change the owner first by calling transferOwnership() (from the current owner address).
Removing the onlyOwner modifier from the mintNFT() function would allow anyone to call the function.
Answering this for anyone else who stumbles across the issue while using the Alchemy tutorial:
In the tutorial, it says to init the contract in your mint method like this:
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");
const contractAddress = "0x81c587EB0fE773404c42c1d2666b5f557C470eED";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
However, if you attempt to call estimateGas() or encodeABI() it will fail with the onlyOwner error.
The solution is to change the third line to:
const nftContract = new web3.eth.Contract(contract.abi, contractAddress, {
from: PUBLIC_KEY
});
This will set a default value of "From" so that when you call estimateGas() on a mint function marked onlyOwner, it will be able to use that from field to see that its the owner calling the estimateGas.
Took forever to figure this out.
I finally figured it out, the contract does not initialize the way I deploy it. So you have to initialize it after deployment.

Error: gas required exceeds allowance or always failing transaction - web3js

I get the following error when I try to deploy a smartcontract using web3js. But if I deploy the same contract using Truffle or geth console, deployment succeeds.
Error: gas required exceeds allowance or always failing transaction
Smart Contract solidity code:
pragma solidity >=0.4.25 <0.6.0;
contract Election {
// Model a Candidate
struct Candidate {
uint id;
string name;
uint voteCount;
}
// Store accounts that have voted
mapping(address => bool) public voters;
// voted event
event votedEvent (
uint indexed _candidateId
);
// Store Candidates
// Read Candidate
mapping(uint => Candidate) public candidates;
// Store Candidates count
uint public candidatesCount;
// Constructor
constructor() public{
addCandidate('ABC');
addCandidate('XYZ');
addCandidate('PQR');
}
function addCandidate(string memory _name) private{
candidatesCount++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
function vote(uint _candidateId) public{
// require that they haven't voted before
require(!voters[msg.sender]);
// require a valid candidate
require(_candidateId > 0 && _candidateId <= candidatesCount);
// record that voter has voted
voters[msg.sender] = true;
// update candidate vote Count
candidates[_candidateId].voteCount ++;
// trigger voted event
emit votedEvent(_candidateId);
}
}
Following is the code, I am using to deploy the smartcontract:
const provider = new HDWalletProvider(mnemonic, nodeAccessToken, 1);
const web3 = new Web3(provider);
const contract = new web3.eth.Contract(abi);
const accounts = await web3.eth.getAccounts();
try{
const deployedContract = await contract.deploy({
data: '0x' + bytecodeData, // Adding '0x' since generated bytecodedata doesn't have '0x' prefix.
arguments: args
});
let result = await deployedContract.send({
from: accounts[0],
gasPrice: 0
})
}catch(e){}
Did anyone else face the same issue?

transfer hash verification in a smart contract

I have a contract which holds tokens on behalf of addresses and transfers them when a signed hash of a transfer is provided.
The contract looks like this
pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
contract Settlement is Ownable {
using SafeMath for uint256;
struct Withdrawal {
uint256 amount;
address token;
uint256 timestamp;
}
// token => (holder => balance)
mapping(address => mapping(address => uint256)) public tokenBalances;
mapping(address => Withdrawal) withdrawals;
function transferInto(address recipient, uint256 amount, address token) public {
//get the tokens
IERC20(token).transferFrom(msg.sender, address(this), amount);
//increase the token balance in the payment contract
tokenBalances[token][recipient] = tokenBalances[token][recipient].add(amount);
}
string constant private prefix = "\u0019Ethereum Signed Message:\n32";
function transfer(address to, uint256 amount, address token, uint8 v, bytes32 r, bytes32 s)
public {
bytes32 paramHash = keccak256(abi.encodePacked(to, amount, token));
address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);
//SafeMath ensures that the signer has enough tokens in their payment account
tokenBalances[token][signer] = tokenBalances[token][signer].sub(amount);
IERC20(token).transfer(to, amount);
}
}
and I have written a function to create the signature which is passed to the transfer function of the contract:
const ethers = require('ethers')
const BigNumber = require('bignumber.js')
const utils = require('web3-utils')
// the purpose of this function is to be able to create BN from exponent numbers like '2e22' they must be formatted as string in this case
const toBN = (num) => utils.toBN(new BigNumber(num).toString(10))
async function signTransfer(recipient, amount, tokenAddress, privateKey){
const wallet = new ethers.Wallet(privateKey)
const txMsg = utils.soliditySha3(recipient, toBN(amount), tokenAddress)
const messageHashBytes = ethers.utils.arrayify(txMsg)
const flatSig = await wallet.signMessage(messageHashBytes)
const sig = ethers.utils.splitSignature(flatSig)
return {
...sig,
hash: messageHashBytes
}
}
module.exports = signTransfer
this works but I had to use both ethers and web3-utils packages to implement this.
how can I replace the soliditySha3 function with an ethers version?
I had a look at the implementation of soliditySha3 and it looks mighty complex.
The thing is that web3js does not seem to have a function to create the messageHashBytes in my function. So I'm stuck with both. It's not super bad, but it would be nice to reduce the number of libraries.
If you're okay just using web3.js for everything, something like this should work:
function signTransfer(recipient, amount, tokenAddress, privateKey) {
return web3.eth.accounts.sign(
web3.utils.soliditySha3(recipient, toBN(amount), tokenAddress),
privateKey);
}