I'm mew to Ethereum/Solidity/Web3.js. I'm trying to use web3.js web.eth.sendsendTransaction() method in order to run a function in a deployed contract on a private chain.
The function I try to execute is:
contract Matematicas{
uint256 ultimaSuma;
uint256 ultimaMultiplicacion;
uint256 contador;
uint256 factorA;
uint256 factorB;
uint256 sumandoA;
uint256 sumandoB;
bytes datosMensaje;...
function multiplica(uint256 a, uint256 b) public{
datosMensaje=msg.data;
factorA=a;
factorB=b;
ultimaMultiplicacion=(a*b);
}
...
}
I call multiplica from Mist browser runnig the following JavaScript code:
var contracAddress="0xXXXXXXXX";
var contractABI=[{"constant":false,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"multiplica","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},...];
var functionABI=$.grep(contractABITercero,function(metodo,index){ return metodo.name=='multiplica';});
functionABI=abiDelaFuncion[0];
var abiByteCode= web3.eth.abi.encodeFunctionCall(functionABI,[document.getElementById('firstNumber').value,document.getElementById('secondNumber').value]);
var transactionObject={from:"0xxxxxxxxxx",to:contractAddress,data:abiByteCode, gas:10000000};
web3.eth.sendTransaction(transactionObject, function(error,hash){......});
If I set firstNumber=1000 and secondNumber=2000 then abiByteCodes happens to be:
0x38e836df00000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000007d0
0x38e836df is the sha of the fuction signature, that is correct;
03e8 is hexadecimal for 1000(firstNumber) right
07d0 is hex for 2000(secondNumber) ok
But data stored in the block chain is:
datosMensaje: 0x38e836df0000000000000000000000000000000000000000000000000000000000**9e0**3e80000000000000000000000000000000000000000000000000000000000**9e0**7d0
factorA:
8520680 (0x8203E8)
factorB:
8521680 (0x8207D0)
What am I doing wrong?
I'm using geth 1.7.3 and Mist 0.9.2 on a Windows 10 64 bit desktop.
P.S. I know there are other ways to call contract functions like instantiating the contract via new web3.eth.Contract(contractABI,contractAddress) but I'm thinking about a project that would require to use the sendTransaction() method
This is due to an error in how remix IDE shows values in the debug tab. If I recover the data from the blockchain using web3.js ver 1.0 method getStorageAt(address,key) I get the expected values.
Related
I followed the direct funding tutorial
I am testing on goerli,
however still getting a revert (tenderly tx explorer)
It is very weird, MustBeSubowner revert.
I dont quite understand it, as msg.sender is the wrapper, and when
i check the subscription owner, it is the wrapper (subId is 1519),
so it should not revert :/
This is how i did the init on goerli:
constructor(address stateAddress) VRFV2WrapperConsumerBase(
0x326C977E6efc84E512bB9C30f76E30c160eD06FB, // LINK Token
0x708701a1DfF4f478de54383E49a627eD4852C816 // VRF Wrapper ) {
keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
fee = 0.25 * 10 ** 18; // in LINK (Varies by network)
This should be ok right?
And i call then:
requestId = requestRandomness(3000000, 3, 1);
I also funded the calling contract with enough LINK
I got the params from:
https://docs.chain.link/docs/vrf/v2/direct-funding/supported-networks/#goerli-testnet
I was expecting to get a fulfillRandomWords callback, but instead got a revert on requestRandomness call.
Hello Vedran
If you compare your code with the example in Create and deploy a VRF v2 compatible contract
You are NOT initializing the
ConfirmedOwner(msg.sender) in the constructor and you must do it.
Suppose I want to design a game where the user places a bet (using the ERC20 token) for a coin toss, and suppose the solidity function within our game contract called to place the bet is bet(uint256 _betAmount, int256 pick).
When playing around with some code, I realized that if the bet() function contains the token.transfer() call (used to place the initial bet before simulating the coin toss), the funds would be transfered from the game contract, and not from the user, even if the caller of bet() is the user. Thus, I would need to use the token.transferFrom() function, but the user would need to set the allowance for the game contract to spend the funds on their behalf.
My question is, how could this be handled in the frontend? Is there a way for a pop-up to show up asking for permission to spend the tokens (thinking of somehting similar to metamask when executing a transaction)?
Basically the user will need to accept two transactions.
But before calling the bet function you need also to wait until the approve function is confirmed.
In a project i developed i also had to handle your exact same case and i did something like this (i used react-moralis to interact with the contract):
const handleBet = async () => {
await approve({
onSuccess: async (tx) => {
await tx.wait(1) // Wait until the transaction is mined
await bet() // Call the bet function
},
onError: () => {
console.log("error") // Handle error however you want
}
})
}
I am writing an automated test suite that needs to test functions against Uniswap v2 style automated market marker: do swaps and use different order routing. Thus, routers need to be deployed.
Are there any existing examples of how to deploy a testable Uniswap v2 style exchange in Brownie? Because Brownie is a minority of smart contract developers, are there any examples for Truffle or Hardhat?
I am also exploring the option of using a mainnet fork, but I am not sure if this operation is too expensive (slow) to be used in unit testing.
Using a local testnet allows you to control very precisely the state of the blockchain during your test. However, it will require you to deploy every contract you need manually.
A fork of the mainnet will save you from having to deploy every contract already deployed on the mainnet. However you will sacrifice control over the environment and will require a connection to a node.
I've deployed Uniswap 2V on a testnet a few times. To do it you will need the bytecode and ABI for the following contracts: UniswapV2Factory, UniswapV2Pair, UniswapV2Router02 (I suppose you want the second version of the router). The Uniswap docs explains very well how to download them from NPM. For the router to work properly you will also need to deploy a WETH contract. I suggest deploying the one from this github page.
Before running this code, just make sure that your chain is running. For hardhat run the following command:
npx hardhat node
Start by connecting your signer to your dev chain:
var provider = new ethers.providers.WebSocketProvider("ws://localhost:8545");
var signer = provider.getSigner();
Using the ethers.js library, you first deploy the factory:
const compiledUniswapFactory = require("#uniswap/v2-core/build/UniswapV2Factory.json");
var uniswapFactory = await new ethers.ContractFactory(compiledUniswapFactory.interface,compiledUniswapFactory.bytecode,signer).deploy(await signer.getAddress());
Then the WETH contract:
const compiledWETH = require("canonical-weth/build/conrtacts/WETH.json";
var WETH = await new ethers.ContractFactory(WETH.interface,WETH.bytecode,signer).deploy();
You can now deploy the router.
const compiledUniswapRouter = require("#uniswap/v2-periphery/build/UniswapV2Router02");
var router = await new ethers.ContractFactory(compiledUniswapRouter.abi,compiledUniswapRouter.bytecode,signer).deploy(uniswapFactory.address,WETH.address);
You will also need to deploy the ERC20 tokens you need (Here is an example with tokens I've written):
const compiledERC20 = require("../../../Ethereum/Ethereum/sources/ERC20.sol/Token.json");
var erc20Factory = new ethers.ContractFactory(compiledERC20.abi,compiledERC20.bytecode,signer);
var erc20_0 = await erc20Factory.deploy("1000000", "Token 0", "5", "T0");
var erc20_1 = await erc20Factory.deploy("1000000", "Token 1", "5", "T1");
The parameters of the deploy function will depend on the constructor of the token you wish to deploy.
You will also want to create pairs using the createPair method of the Uniswap factory.
uniswapFactory.createPair(erc20_0.address,erc20_1.address);
Keep in mind that in the pair the tokens will be ordered arbitrarly by the contract. ERC20_0 might not be the first of the two.
After that just wait for all the transactions to go through and you should be good to start your test.
For a quick and easy set up I would use Hardhat's mainnet fork.
Like #Xavier said, using a mainnet fork means you don't have to deploy each contract you want to interact with. If you're wanting to test your contract against multiple exchanges, this would be the easiest way. It does however require a connection to a node and therefore your unit tests will run slower.
As an example, let's say I want to test the following contract, which swaps ETH for an ERC20 token on Uniswap using the swapExactETHForTokens method.
pragma solidity ^0.6.6;
interface IUniswap {
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline)
external
payable
returns (uint[] memory amounts);
function WETH() external pure returns (address);
}
contract UniswapTradeExample {
IUniswap uniswap;
// Pass in address of UniswapV2Router02
constructor(address _uniswap) public {
uniswap = IUniswap(_uniswap);
}
function swapExactETHForTokens(uint amountOutMin, address token) external payable {
address[] memory path = new address[](2);
path[0] = uniswap.WETH();
path[1] = token;
uniswap.swapExactETHForTokens{value: msg.value}(
amountOutMin,
path,
msg.sender,
now
);
}
}
From the Hardhat docs, the first thing to do is set up a connection to an archive node with Alchemy, which is free to use.
Once you have a url for the node, add it as a network to your hardhat.config.js file:
networks: {
hardhat: {
forking: {
url: "https://eth-mainnet.alchemyapi.io/v2/<key>",
blockNumber: 14189520
}
}
}
If you set blockNumber, Hardhat will fork off this block each time. This is recommended if you're using a test suite and want your tests to be deterministic.
Finally, here's the test class, which tests the swapExactETHForTokens in the above contract. As an example I'm swapping 1 ETH for DAI.
const { assert } = require("chai");
const { ethers } = require("hardhat");
const ERC20ABI = require('./ERC20.json');
const UNISWAPV2ROUTER02_ADDRESS = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
const DAI_ADDRESS = "0x6b175474e89094c44da98b954eedeac495271d0f";
describe("UniswapTradeExample", function () {
it("Swap ETH for DAI", async function () {
const provider = ethers.provider;
const [owner, addr1] = await ethers.getSigners();
const DAI = new ethers.Contract(DAI_ADDRESS, ERC20ABI, provider);
// Assert addr1 has 1000 ETH to start
addr1Balance = await provider.getBalance(addr1.address);
expectedBalance = ethers.BigNumber.from("10000000000000000000000");
assert(addr1Balance.eq(expectedBalance));
// Assert addr1 DAI balance is 0
addr1Dai = await DAI.balanceOf(addr1.address);
assert(addr1Dai.isZero());
// Deploy UniswapTradeExample
const uniswapTradeExample =
await ethers.getContractFactory("UniswapTradeExample")
.then(contract => contract.deploy(UNISWAPV2ROUTER02_ADDRESS));
await uniswapTradeExample.deployed();
// Swap 1 ETH for DAI
await uniswapTradeExample.connect(addr1).swapExactETHForTokens(
0,
DAI_ADDRESS,
{ value: ethers.utils.parseEther("1") }
);
// Assert addr1Balance contains one less ETH
expectedBalance = addr1Balance.sub(ethers.utils.parseEther("1"));
addr1Balance = await provider.getBalance(addr1.address);
assert(addr1Balance.lt(expectedBalance));
// Assert DAI balance increased
addr1Dai = await DAI.balanceOf(addr1.address);
assert(addr1Dai.gt(ethers.BigNumber.from("0")));
});
});
Note the const ERC20ABI = require('./ERC20.json'); at the top, which imports the ERC20ABI needed to fetch the DAI contract and use it's balanceOf() method.
That's all. Running npx hardhat test should show that this test passes.
The answer from Xavier Hamel set me in the right direction.
Unfortunately, Uniswap v2 and its clones cannot be recompiled and redeployed without editing the source code. This is because
Router depends on UniswapV2Library
UniswapV2Library has the initial code hash of UniswapV2Factory hardcoded in pairFor() function
Any recompilation may result in a different UniswapV2Factory and thus different hash
Router would fail to route any trades because pairFor fails because it generates an invalid pair contract address
This was a pesky problem. I ended up building the whole library and tooling to solve it: Please meet Smart contacts for testing. It is based on Sushiswap v2 repo, as their contracts were the best maintained.
I'm fairly new to Ethereum smart contracts, so this might be a stupid question, but I need someone to help me out. I've set up Galanche on my machine (MacOS 11) and written a very simple currency smart contract (I don't intend to use it as an actual currency, I just want to learn about smart contracts) using truffle.
I've compiled the contract and deployed it to my Galanche blockchain successfully.
Now, I want to interact with it using web3.js. I have set up a nodejs project and installed web3. As a first test, I ran the following script:
const Web3 = require("web3");
const fs = require("fs");
const web3 = new Web3("http://192.168.178.49:7545");
const abi = JSON.parse(
fs.readFileSync("path/to/compiled/MyCoin.json").toString()
).abi;
const MyCoin = new web3.eth.Contract(
abi,
// My contract's address
"0x3265aA0A2c3ac15D0eDd67BC0fa62A446c112F98"
);
(async () => {
console.log("Starting!");
var coinCount = await MyCoin.methods
.getTotalCoins()
.call({ from: "0x2d0616BF48214513f70236D59000F1b4f395a2Fd" });
console.log("Current registered MyCoin tokens:", coinCount);
})();
The address 0x2d0616BF48214513f70236D59000F1b4f395a2Fd is the first address displayed to me in Galanche
It works as expected and returns the default amount of coins.
Now, I want to run a method called buyMyCoin which requires a payment. I tried running:
...
MyCoin
.methods
.buyMyCoin
.send(
{
from: '0x2d0616BF48214513f70236D59000F1b4f395a2Fd',
value: some_amount_of_wei
}
);
...
I'd expect that when I run this node.js script again, the first part would tell me that there are <n> total coins, but it doesn't. It just returns the same value as the last time.
Am I doing something wrong with web3.js or is this an issue with my contract?
BTW: I didn't see any funds leave the address 0x2d0616BF48214513f70236D59000F1b4f395a2Fd in Galanche, so I'm pretty sure it's not my contract...
I expect that somewhere I'd have to sign into this address using its public key, but I can't find anything about that in the web3.js docs that isn't very ambiguous...
Edit: Here's the code for my buyMyCoin method:
...
/**
* #dev Buy MyCoin
*/
function buyMyCoin() external payable {
require(msg.value > 1 gwei, "Minimum transaction is 1 gwei"); // Not very much
uint256 amount = convert(msg.value, conversionRate, true);
balances[msg.sender].owner = payable(msg.sender);
balances[msg.sender].amount += amount;
totalCoins += amount;
}
...
turns out it was just me being stupid! I was trying to run the transaction with an outrageously low amount of ether (4 gwei) which is, of course, so small that it can't be seen in the Ganache app.
The reason I was seeing no new coins being created was because my conversion code rounded the result to 0.
I want to be able to watch the state/storage of an ethereum contract and know for instance when some conditions are satisfied. For instance, one account value is greater than 200, another map has more than 30 keys, etc.
What can I use for this? Is there a SaaS platform that can be used for this purpose?
EDIT: I forgot to mention that I am NOT the owner of the contract. I simply want to watch somebody's else contract.
Events are supported for this purpose.
Event Documentation
Example:
contract SomeContract {
struct AccountData {
address account;
uint value;
}
...
event AccountValueChange(address account, uint value, bytes msg);
...
function someAction() {
AccountData accountData;
// some activity with accountData...
if (accountData.value > 200) {
AccountValueChange(accountData.address, accountData.value, "Some message");
}
}
}
You can listen for the events in your client
const someContract = web3.eth.contract(abi).at(address);
myContract.events.AccountValueChange({
filter: {//Optional event filters},
fromBlock: 0
}, function(error, event){ console.log(event); })
.on('data', function(event){
console.log(event);
})
.on('error', console.error);
EDIT: Updated client code to listen to all events instead of just a single fired event.
Short answer is that you'll have to probe the EVM yourself to make this happen and then run your own node on the network that you can monitor. There is no public project I can find that will do this, and the RPC api does not provide any way to accomplish it. I used a modified Geth binary with custom transaction filters coded in and mailgun to send me emails when my conditions were met.
Events will not solve your issue because events must be included in the contract at the time of creation.