multisig wallet submitTransaction - ethereum

I have a smart contract MyContract which is owned by a multisig wallet (Gnosis). When I submitTransaction from web3/testrpc on the multisig wallet for executing a function from MyContract with its parameters, and confirm the transaction, it is the fallback function from MyContract which is executed in the end. So it seems like the function call which is passed as raw data to the Gnosis submitTransaction method is not well interpreted. I have tried 2 ways to get the transaction data and both give the same result:
function from MyContract that I want to execute on mycontract2 instance through Multisig:
function setTransferOperator(address newOperator)
data generated using ethereumjs-abi lib:
var data = abi.methodID('setTransferOperator', ['address']).toString('hex') + abi.rawEncode(['address'], [accounts[8]]).toString('hex');
return gnosiswallet.submitTransaction(mycontract2.address, 0, data, {from: accounts[0]});
the same data is generated using truffle:
var data2 = mycontract2.setTransferOperator.request(accounts[8]);
The transaction with data succeeds in a simple scenario when mycontract2 is owned by a standard account

Related

Get list of recent added/deployed smart contracts

Is there a way to retrieve the most recent added/deployed smart contracts to the ethereum chain?
Thanks a lot for any advice.
Regards,
JR
Newly deployed contract addresses are not directly available through the node RPC API (and its wrappers such as ethersjs and web3js), but you can build a script that
Subscribes to newly published blocks
Loops through transaction receipts on the block
And searches for contractAddress property of the transaction receipt
The contractAddress property returns null if the transaction does not deploy a contract (most transactions) or an address if the transaction deploys a contract.
The above mentioned approach only retrieves contracts that were deployed directly - by sending a transaction with empty to field and data field containing the contract bytecode.
It does not retrieve contracts that were deployed using an internal transaction. For example it would not catch the following Hello contract deployment (that is deployed by executing the deployHello() function).
pragma solidity ^0.8;
contract Hello {}
contract HelloFactory {
event Deployed(address);
function deployHello() external {
// deploys a new instance of the `Hello` contract to a new address
address deployedTo = address(
new Hello()
);
emit Deployed(deployedTo);
}
}
If you want to retrieve deployments of these contracts as well, then you'd need to debug each newly produced block and search for the create and create2 opcodes (each of them deploys a new contract, they take different input arguments).
So overall, it's not a simple task but it's doable.
It's generally discouraged to recommend any specific 3rd party APIs and tools here at StackOverflow. But I'm guessing that there are already some existing services that do all of this on their backend, and are able to return the aggregated list of newly deployed contracts as a result.
Thanks to the help of Petr Hejda I created the following Python code:
import sys
import time
from web3 import Web3
def connect():
# infura API key
API_KEY = "INFURA_API_KEY"
# change endpoint to mainnet or ropsten or any other of your account
url = f"https://mainnet.infura.io/v3/{API_KEY}"
w3 = Web3(Web3.HTTPProvider(url))
# res = w3.isConnected()
# print(res)
return w3
def get_latest_block(connection):
return connection.eth.get_block('latest')
def get_latest_block_id(block_information):
return block_information['number']
def search_new_contracts(connection, block_information):
block_transactions = block_information['transactions']
# print(block_transactions)
for transaction in block_transactions:
transaction_data = connection.eth.getTransaction(transaction)
if transaction_data['to'] == "":
print(f"Contract creation transaction: {transaction_data}")
print("Block searching done")
if __name__ == "__main__":
current_block_number = sys.maxsize
connection = connect()
while True:
latest_block = get_latest_block(connection)
latest_block_id = get_latest_block_id(latest_block)
if current_block_number is not latest_block_id:
print(f'New block detected: {latest_block_id}')
search_new_contracts(connection, latest_block)
current_block_number = latest_block_id
Problem is that it is slow so I have to see if I can speed things up.

Override the gasPrice in ethers.js contract interaction

How can I set the gasPrice in a contract interaction using ethers.js? I'm trying to override the gasPrice in the code below:
let txPromise = contract.populateTransaction.runAdventureVRF(0, false, { gasPrice: 800000 })
walletSigner.sendTransaction(txPromise)
and i'm receiving the error transaction underpriced. If i try to log txPromise.overrides it is undefined, which makes me think the gas price is never being set.
docs
additional code
const provider = new ethers.providers.AlchemyProvider('matic', process.env.ALCHEMY_API_KEY)
const wallet = new ethers.Wallet(process.env.PK)
const abi = '[{"inputs":[{"internalType":"uint256","name":"_teamId","type":"uint256"},{"internalType":"bool","name":"_energy","type":"bool"}],"name":"runAdventureVRF","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]'
const contract = new ethers.Contract(address, abi, provider);
let walletSigner = wallet.connect(provider)
One solution is to add the gas price as an override to your transaction:
walletSigner.sendTransaction(txPromise, {gasPrice: ethers.utils.parseUnits('100', 'gwei'), gasLimit: 1000000});
This is the only solution I could find as getGasPrice() and estimateGas() were returning a empty json array. I don't know if it has to do with the provider (alchemy) or why those are failing.
The specific syntax to override the gas price is here:
Ethers Override Transaction Gas Price Manually
It's also in the following Ethers docs, but not as clear (if you don't know the syntax):
Ethers Contract Functions Send
At the time of this post, the default gas value of all my transactions is 1.5 gwei which is nowhere near enough on the matic network. This will also hang up the transaction indefinitely until you send a new transaction with the same nonce value. Even if you resolve your gas issue, until you deal with the hung transaction, other transactions will stack up behind it.
If you just want to increase gasLimit by a certain amount, you can make a helper function to do so:
const increaseGasLimit = (estimatedGasLimit: BigNumber) => {
return estimatedGasLimit.mul(130).div(100) // increase by 30%
}
And use it like this:
const estimatedGas = await contract.estimateGas.method(args)
const tx = await contract.method(args, { gasLimit: increaseGasLimit(estimatedGas) })

How do I solve the Smart Contract error "returned values aren't valid"?

I am trying to read basic information from a smart contract using web3.js (GRAPH Token):
https://etherscan.io/address/0xc944e90c64b2c07662a292be6244bdf05cda44a7#code
This is my super simple react web3.js setup:
import Web3 from 'web3';
...
useEffect(() => {
const start = async () => {
const web3 = new Web3('https://bsc-dataseed1.binance.org:443')
const abi = [{"inputs":[{"internalType":"uint256","name":"_initialSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewPendingOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"addMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"removeMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
const address = '0xc944E90C64B2c07662A292be6244BDf05Cda44a7'
const contract = new web3.eth.Contract(abi, address)
console.log(contract);
const i = await contract.methods.getName().call()
console.log(i); // => ERROR
}
start()
}, [])
And it throws error:
Error: Returned values aren't valid, did it run Out of Gas? You might also see this error if you are not using the correct ABI for the contract you are retrieving data from, requesting data from a block number that does not exist, or querying a node which is not fully synced.
This is a known and misleading error which usually means that the address or the contract abi is invalid but I verified it is correct.
I researched this error for two days but didn't manage to solve this issue... any suggestions?
You're trying to interact with an Ethereum contract, using a BSC (Binance Smart Chain) Web3 provider (in your case https://bsc-dataseed1.binance.org:443). This results in trying to call the getName() function on the BSC address (which doesn't contain any contract).
Ethereum and BSC are different networks, unrelated to each other.
Solution: Use an Ethereum mainnet provider (for example Infura is widely used).

uniswap low level swap call

I can use the router02 function to swap tokens on uniswap:
route02.swapExactTokensForTokens(amtIn, amtOut,
[t1.address, t2.address], addr, deadline(), {gasLimit: 4000000});
But how to call the low level swap function for uniswap directly? Here is my code but it didn't work. I have already send tokens to uni_v2_address before this function call.
const ethers = require('ethers');
const uni = new ethers.Contract(UNI_V2_ADDRESS, IUniswapV2Pair.abi, wallet);
let amt0out = BigInt(1) * BigInt(10**16);
let amt1out = BigInt(0);
//do swap
let tx = await uni.swap(amt0out, amt1out,
addr, 0x0, {gasLimit: 4000000});
Remove the fourth parameter "data" like this:
let tx = await uni.swap(amt0out, amt1out, addr, {gasLimit: 4000000});
Passing anything in the fourth "data" parameter initiates a Flash Swap, optimistically transferring tokens to addr and attempting to call a function named "uniswapV2Call" on the addr as described here:
Uniswap Flash Swaps Documentation
This really needs to be done from a contract, hence the router. This is not safe to do without a contract, as you either have to handle the callback (like above using flashswap) or you have to send the tokens to the contract and then call the swap function. If not done in same transaction you will lose the tokens

web3 calls Solidity contract function with extra parameter?

In the http://truffleframework.com/tutorials/pet-shop example, there is the following contract, and the function adopt(uint petId) has only one parameter.
contract Adoption {
address[16] public adopters;
function adopt(uint petId) public returns (uint) {
require(petId >= 0 && petId <= 15);
adopters[petId] = msg.sender;
return petId;
}
function getAdopters() public returns (address[16]) {
return adopters;
}
}
However, in the javascript code app.js, the handleAdopt function call the contract function using the following code.
App.contracts.Adoption.deployed().then(function(instance) {
adoptionInstance = instance;
return adoptionInstance.adopt(petId, {from: account});
})
The function is called with the extra object {from: account}. Why? And is this parameter discarded in the solidity code?
BTW, there is an undefined global variable web3? Is the value be assigned by the MetaMask extension?
That is the transactionObject which describes general information about all transaction calls (gas limit, price, amount of ether to send, etc.). The JS code you posted is using the web3 library. That's not the direct call to the contract API. The web3 library converts it to an RPC. The transactionObject comes after all of the contract parameters. There is another parameter that comes after which is the callback with the results of the contract call (see here).
These are all of the options for the transactionobject described from the docs:
from: String - The address for the sending account. Uses the web3.eth.defaultAccount property, if not specified.
to: String - (optional) The destination address of the message, left undefined for a contract-creation transaction.
value: Number|String|BigNumber - (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction.
gas: Number|String|BigNumber - (optional, default: To-Be-Determined) The amount of gas to use for the transaction (unused gas is refunded).
gasPrice: Number|String|BigNumber - (optional, default: To-Be-Determined) The price of gas for this transaction in wei, defaults to the mean network gas price.
data: String - (optional) Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code.
nonce: Number - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.