Ethereum transaction giving error 'invalid sender' - ethereum

This is how my contract looks like -
pragma solidity >=0.4.25 <0.8.0;
contract Calculator {
uint public result;
event Added(address caller, uint a, uint b, uint res);
constructor() public {
result = 777;
}
function add(uint a, uint b) public returns (uint, address) {
result = a + b;
emit Added(msg.sender, a, b, result);
return (result, msg.sender);
}
}
Above contract is deployed on Ropsten test net. And I am trying to invoke the add(...) function with a transaction. And my code looks like this -
const accountAddress = rtUtil.getAccountAddress();
const accountPk = Buffer.from(rtUtil.getAccountAddressPk(), "hex");
const contract = await rtUtil.getCalculatorContract();
const data = contract.methods.add(3, 74).encodeABI();
const web3 = rtUtil.getWeb3();
const taxCount = await web3.eth.getTransactionCount(accountAddress);
const txObject = {
nonce: web3.utils.toHex(taxCount),
to: rtUtil.getCalculatorContractAddress(),
value: web3.utils.toHex(web3.utils.toWei('0', 'ether')),
gasLimit: web3.utils.toHex(2100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('6', 'gwei')),
data: data
};
const commmon = new Common({chain: "ropsten", hardfork: "petersburg"});
const tx = Transaction.fromTxData(txObject, {commmon});
tx.sign(accountPk);
const serializedTx = tx.serialize();
const raw = web3.utils.toHex(serializedTx);
const transaction = await web3.eth.sendSignedTransaction(raw);
And when I run the code I get error -
Uncaught Error: Returned error: invalid sender
Process exited with code 1
My Nodejs versions is v15.1.0
And my package.json dependencies are -
"dependencies": {
"#ethereumjs/common": "^2.0.0",
"#ethereumjs/tx": "^3.0.0",
"#truffle/contract": "^4.2.30",
"#truffle/hdwallet-provider": "^1.2.0",
"web3": "^1.3.0"
}
Can anyone tell me what I am doing wrong?
Thanks in advance.

In your txObject, you need to specific the chain id.
Add Ropsten's chain id, 3 into txObject.
const txObject = {
nonce: web3.utils.toHex(taxCount),
to: rtUtil.getCalculatorContractAddress(),
value: web3.utils.toHex(web3.utils.toWei('0', 'ether')),
gasLimit: web3.utils.toHex(2100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('6', 'gwei')),
data: data,
chainId: web3.utils.toHex(3)
};

You need to include from in your txObject:
const txObject = {
from: accountAddress,
nonce: web3.utils.toHex(taxCount),
to: rtUtil.getCalculatorContractAddress(),
value: web3.utils.toHex(web3.utils.toWei('0', 'ether')),
gasLimit: web3.utils.toHex(2100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('6', 'gwei')),
data: data
};

Related

Hardhat, ether.js. TypeError: deployer.sendTransaction is not a function error. Trying to execute exactInput UniswapV3 function

Im trying to execute a swap to buy Uni using UniswapV3 interface.
It sends me this error related to the sendTransaction() function and I dont understand why as a lot of examples that I have seen use it this way.
Im using hardhat as you can see and calling the getToken() from another script and deploying on goerli network. Function to check UNI wallet balnceOf() at the end works fine.
Also what advice would you recommend me to improve my code?
This is the code:
const { ethers, getNamedAccounts, network } = require("hardhat")
const {abi: V3SwapRouterABI} = require('#uniswap/v3-periphery/artifacts/contracts/interfaces/ISwapRouter.sol/ISwapRouter.json')
const FEE_SIZE = 3
function encodePath(path, fees) {
if (path.length != fees.length + 1) {
throw new Error('path/fee lengths do not match')
}
let encoded = '0x'
for (let i = 0; i < fees.length; i++) {
// 20 byte encoding of the address
encoded += path[i].slice(2)
// 3 byte encoding of the fee
encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0')
}
// encode the final token
encoded += path[path.length - 1].slice(2)
return encoded.toLowerCase()
}
async function getToken() {
// const signer = provider.getSigner()
const deadline = Math.floor(Date.now()/1000) + (60*10)
const wethToken= "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
const Uni= "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
const UniswapRouter="0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
const path = encodePath([wethToken, Uni], [3000])
console.log(path)
const { deployer } = await getNamedAccounts()
const UniV3Contract = await ethers.getContractAt(
V3SwapRouterABI,
UniswapRouter,
deployer
)
const params = {
path: path,
recipient:deployer,
deadline: deadline,
amountIn: ethers.utils.parseEther('0.01'),
amountOutMinimum: 0
}
const encodedData = UniV3Contract.interface.encodeFunctionData("exactInput", [params])
const txArg = {
to: UniswapRouter,
from: deployer,
data: encodedData,
gasLimit: ethers.utils.hexlify(1000000)
}
const tx = await deployer.sendTransaction(txArg)
console.log('tx: ', tx)
const IUni = await ethers.getContractAt(
"IERC20",
Uni,
deployer
)
const UniBlance = await IUni.balanceOf(deployer)
console.log(`Got ${UniBlance.toString()} UNI`)
}
module.exports = { getToken }
Without using the hardhat enviorment:
const {abi: V3SwapRouterABI} = require('#uniswap/v3-periphery/artifacts/contracts/interfaces/ISwapRouter.sol/ISwapRouter.json')
const { ethers } = require("ethers")
require("dotenv").config()
const INFURA_URL_TESTNET = process.env.INFURA_URL_TESTNET
const PRIVATE_KEY = process.env.PRIVATE_KEY
const WALLET_ADDRESS = process.env.WALLET_ADDRESS
// now you can call sendTransaction
const wethToken= "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"
const Uni= "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
const UniswapRouter="0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
const UniV3Contract = new ethers.Contract(
UniswapRouter,
V3SwapRouterABI
)
const provider = new ethers.providers.JsonRpcProvider(INFURA_URL_TESTNET)
const wallet = new ethers.Wallet(PRIVATE_KEY)
const signer = wallet.connect(provider)
const FEE_SIZE = 3
function encodePath(path, fees) {
if (path.length != fees.length + 1) {
throw new Error('path/fee lengths do not match')
}
let encoded = '0x'
for (let i = 0; i < fees.length; i++) {
// 20 byte encoding of the address
encoded += path[i].slice(2)
// 3 byte encoding of the fee
encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0')
}
// encode the final token
encoded += path[path.length - 1].slice(2)
return encoded.toLowerCase()
}
async function getToken() {
const path = encodePath([wethToken, Uni], [3000])
const deadline = Math.floor(Date.now()/1000) + (60*10)
const params = {
path: path,
recipient: WALLET_ADDRESS,
deadline: deadline,
amountIn: ethers.utils.parseEther('0.01'),
amountOutMinimum: 0
}
const encodedData = UniV3Contract.interface.encodeFunctionData("exactInput", [params])
const txArg = {
to: UniswapRouter,
from: WALLET_ADDRESS,
data: encodedData,
gasLimit: ethers.utils.hexlify(1000000)
}
const tx = await signer.sendTransaction(txArg)
console.log('tx: ', tx)
const receipt = tx.wait()
console.log('receipt: ', receipt)
}
module.exports = { getToken }
I could not find documentation for getNamedAccounts but when I check the source code, I get this signature
getNamedAccounts: () => Promise<{
[name: string]: Address;
}>;
this just returns an array of account addresses and used in hardhat.config.js
namedAccounts: {
deployer: {
default: 0, // by default take the first account as deployer
1: 0,
},
},
to send the transaction programmatically:
const { ethers } = require("ethers");
const provider = new ethers.providers.JsonRpcProvider(INFURA_TEST_URL);
const wallet = new ethers.Wallet(WALLET_SECRET);
const signer = wallet.connect(provider);
// now you can call sendTransaction
const tx = await signer.sendTransaction(txArg);

Unable to initialize OpenZeppelin Clone contract during Hardhat Test (Error: VM Exception)

I'm trying to create clones of my implementation contract (EIP-1167) using the OpenZeppelin Clones library, however I keep getting a VM Exception Error.
This is the 'Initialize' function of my Implementation contract:
contract Whoopy is Initializable, VRFConsumerBaseV2, KeeperCompatible {
function initialize(address _whoopyCreator) public initializer {
VRFConsumerBaseV2.initialise(vrfCoordinatorV2);
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
s_raffleState = RaffleState.CLOSED;
s_lastTimeStamp = block.timestamp;
whoopyCreator = _whoopyCreator;
i_vrfCoordinator.addConsumer(subscriptionId, address(this));
emit NewConsumerAdded(address(this));
}
This is my CloneFactory:
pragma solidity ^0.8.8;
import "#openzeppelin/contracts/proxy/Clones.sol";
contract WhoopyFactory {
address public implementationContract;
address[] public allClones;
event NewClone(address indexed _instance);
mapping(address => address) public whoopyList;
constructor(address _implementation) {
implementationContract = _implementation;
}
function createClone(address _whoopyCreator) payable external returns (address instance) {
instance = Clones.clone(implementationContract);
(bool success, ) = instance.call{value: msg.value}(abi.encodeWithSignature("initialize(address)", _whoopyCreator));
require(success==true, "initialize did not return true");
allClones.push(instance);
whoopyList[_whoopyCreator] = instance;
emit NewClone(instance);
return instance;
}
This is the test I am running:
const { assert, expect } = require("chai")
const { ethers, upgrades } = require("hardhat")
const { networkConfig } = require("../../helper-hardhat-config")
const fs = require("fs")
const path = require("path")
const { web3, Contract } = require("web3")
const getGas = async (tx) => {
const receipt = await ethers.provider.getTransactionReceipt(tx.hash)
return receipt.gasUsed.toString()
}
let whoopy,
Whoopy,
WhoopyFactory,
wf,
whoopyStandaloneGas,
whoopyFactoryGas,
clonedContract,
accountConnectedClone,
wCreator,
wallet,
addr1,
addr2
describe("Whoopy + WhoopyFactory", function () {
it("Initialises contract correctly", async function () {
provider = ethers.provider
addr1 = new ethers.Wallet("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", provider)
addr2 = new ethers.Wallet("0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", provider)
Whoopy = await ethers.getContractFactory("Whoopy", addr1)
whoopy = await Whoopy.deploy()
await whoopy.deployed()
const dir = path.resolve(
__dirname,
"/Users/boss/hardhat-smartcontract-lottery/artifacts/contracts/Whoopy.sol/Whoopy.json"
)
const file = fs.readFileSync(dir, "utf8")
const json = JSON.parse(file)
const abi = json.abi
WhoopyFactory = await ethers.getContractFactory("WhoopyFactory", addr1)
wf = await WhoopyFactory.deploy(whoopy.address)
await wf.deployed()
wf.connect(addr2)
const tx = await wf.createClone("0x70997970C51812dc3A010C7d01b50e0d17dc79C8", {
value: ethers.utils.parseUnits("1", "ether"),
})
console.log(tx)
const txReceipt = await tx.wait(1)
console.log(txReceipt)
})
})
When I run this test, I get the following error:
Error: VM Exception while processing transaction: reverted with reason string 'initialize did not return true'
This exact same code works perfectly when I try it in Remix, so I assume the issue has something to do with Hardhat.
Does anyone have any idea where the issue is? I've been racking my head for days but can't seem to figure out. I'd be extremely grateful if someone can point me in the right direction.
Thanks!
NOTE: Here is my hardhat config (in case it makes a difference):
require("#nomiclabs/hardhat-waffle")
require("#nomiclabs/hardhat-etherscan")
require("hardhat-deploy")
require("solidity-coverage")
require("hardhat-gas-reporter")
require("hardhat-contract-sizer")
require("dotenv").config()
require("#nomiclabs/hardhat-ethers");
// require('#openzeppelin/contracts');
const RINKEBY_RPC_URL = process.env.RINKEBY_RPC_URL
const PRIVATE_KEY = process.env.PRIVATE_KEY
const COINMARKETCAP_API_KEY = process.env.COINMARKETCAP_API_KEY
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY
/** #type import('hardhat/config').HardhatUserConfig */
module.exports = {
defaultNetwork: "hardhat",
networks: {
hardhat: {
chainId: 31337,
blockConfirmations: 1
},
localhost: {
chainId: 31337,
},
rinkeby: {
chainId: 4,
blockConfirmations: 6,
url: RINKEBY_RPC_URL,
accounts: [PRIVATE_KEY]
}
},
solidity: "0.8.8",
gasReporter: {
enabled: true,
currency: "USD",
outputFile: "gas-report.txt",
noColors: true,
// coinmarketcap: process.env.COINMARKETCAP_API_KEY,
},
namedAccounts: {
deployer: {
default: 0,
},
player: {
default: 1,
}
},
mocha: {
timeout: 900000,
},
etherscan: {
apiKey: {
rinkeby: ETHERSCAN_API_KEY,
// kovan: ETHERSCAN_API_KEY,
// polygon: POLYGONSCAN_API_KEY,
},
},
};

Why am I getting incorrect WBTC when swapping it with DAI using Uniswap?

Hi I created a smart contract but when I swapped 1 Million DAI token I am getting only ~3379786784 WEI (~34 WBTC) but when I am checking its value on UNISWAP website it is showing 43 WBTC.
I am using ganache-cli with mainnet fork. Using truffle to test the smart contract.
test-uniswap.js
const BN = require("bn.js");
const IERC20 = artifacts.require("IERC20");
const TestUniswap = artifacts.require("TestUniswap");
contract("TestUniswap", (accounts) =>{
const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
const DAI_WHALE = "0xF977814e90dA44bFA03b6295A0616a897441aceC";
const WBTC = "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599";
const WHALE = DAI_WHALE;
const AMOUNT_IN = new BN(10).pow(new BN(18)).mul(new BN(1000000));
const AMOUNT_OUT_MIN = 1;
const TOKEN_IN = DAI;
const TOKEN_OUT = WBTC;
const TO = accounts[0];
it("should swap", async ()=>{
const tokenIn = await IERC20.at(TOKEN_IN);
const tokenOut = await IERC20.at(TOKEN_OUT);
const testUniswap = await TestUniswap.new();
console.log(`outbefore ${await tokenOut.balanceOf(TO)}`);
await tokenIn.approve(testUniswap.address, AMOUNT_IN, {from: WHALE});
await testUniswap.swap(
tokenIn.address,
tokenOut.address,
AMOUNT_IN,
AMOUNT_OUT_MIN,
TO,
{
from:WHALE,
}
);
console.log(`out ${await tokenOut.balanceOf(TO)}`);
});
});
TestUniswap.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "./interfaces/IERC20.sol";
import "./interfaces/Uniswap.sol";
contract TestUniswap{
address private constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function swap(
address _tokenIn, //Token trading in for
address _tokenOut, //Token that we want
uint256 _amountIn,
uint256 _amountOutMin,
address _to
) external{
//Transferring the token to this contract that we want to swap
IERC20(_tokenIn).transferFrom(msg.sender, address(this), _amountIn);
IERC20(_tokenIn).approve(UNISWAP_V2_ROUTER, _amountIn);
address[] memory path;
path = new address[](3);
path[0] = _tokenIn;
path[1] = WETH;
path[2] = _tokenOut;
IUniswapV2Router(UNISWAP_V2_ROUTER).swapExactTokensForTokens(
_amountIn,
_amountOutMin,
path,
_to,
block.timestamp);
}
}
Whole project
https://github.com/vinayprolitus/uniswap

Simple Open Auction example contract in Solidity docs doesn't pay beneficiary

I tried the Simple Open Auction example (https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#simple-open-auction) from the Solidity docs with ganache-cli and truffle. In migrations/2_deploy_contracts.js I set up:
var SimpleAuction = artifacts.require("./SimpleAuction.sol");
module.exports = function(deployer) {
deployer.deploy(SimpleAuction, 300, "0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286");
};
With "0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286" the address of account 1 in ganache.
In truffle console, I executed the following commands to simulate an auction (and I waited 300 seconds before calling auction.auctionEnd(), which succeeded):
auction = SimpleAuction.at(SimpleAuction.address)
account1 = web3.eth.accounts[1]
account2 = web3.eth.accounts[2]
account3 = web3.eth.accounts[3]
account4 = web3.eth.accounts[4]
auction.bid({from: account2, value: web3.toWei(10, "ether")})
auction.bid({from: account3, value: web3.toWei(13, "ether")})
auction.bid({from: account4, value: web3.toWei(15, "ether")})
auction.withdraw({from: account2})
auction.withdraw({from: account3})
auction.auctionEnd()
web3.fromWei(web3.eth.getBalance(account1).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account2).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account3).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account4).toString(), "ether")
After this, the balances are:
100
99.9936296
99.9945537
84.9945537
Account 4 has won the auction and paid 15 eth, but I expected account 1 to have a balance of 115 eth, because this account is the beneficiary. I suppose the example code, which I copied verbatim, doesn't have a bug, so what am I doing wrong here?
The contract code is:
pragma solidity ^0.4.22;
contract SimpleAuction {
// Parameters of the auction. Times are either
// absolute unix timestamps (seconds since 1970-01-01)
// or time periods in seconds.
address public beneficiary;
uint public auctionEnd;
// Current state of the auction.
address public highestBidder;
uint public highestBid;
// Allowed withdrawals of previous bids
mapping(address => uint) pendingReturns;
// Set to true at the end, disallows any change
bool ended;
// Events that will be fired on changes.
event HighestBidIncreased(address bidder, uint amount);
event AuctionEnded(address winner, uint amount);
// The following is a so-called natspec comment,
// recognizable by the three slashes.
// It will be shown when the user is asked to
// confirm a transaction.
/// Create a simple auction with `_biddingTime`
/// seconds bidding time on behalf of the
/// beneficiary address `_beneficiary`.
constructor(
uint _biddingTime,
address _beneficiary
) public {
beneficiary = _beneficiary;
auctionEnd = now + _biddingTime;
}
/// Bid on the auction with the value sent
/// together with this transaction.
/// The value will only be refunded if the
/// auction is not won.
function bid() public payable {
// No arguments are necessary, all
// information is already part of
// the transaction. The keyword payable
// is required for the function to
// be able to receive Ether.
// Revert the call if the bidding
// period is over.
require(
now <= auctionEnd,
"Auction already ended."
);
// If the bid is not higher, send the
// money back.
require(
msg.value > highestBid,
"There already is a higher bid."
);
if (highestBid != 0) {
// Sending back the money by simply using
// highestBidder.send(highestBid) is a security risk
// because it could execute an untrusted contract.
// It is always safer to let the recipients
// withdraw their money themselves.
pendingReturns[highestBidder] += highestBid;
}
highestBidder = msg.sender;
highestBid = msg.value;
emit HighestBidIncreased(msg.sender, msg.value);
}
/// Withdraw a bid that was overbid.
function withdraw() public returns (bool) {
uint amount = pendingReturns[msg.sender];
if (amount > 0) {
// It is important to set this to zero because the recipient
// can call this function again as part of the receiving call
// before `send` returns.
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) {
// No need to call throw here, just reset the amount owing
pendingReturns[msg.sender] = amount;
return false;
}
}
return true;
}
/// End the auction and send the highest bid
/// to the beneficiary.
function auctionEnd() public {
// It is a good guideline to structure functions that interact
// with other contracts (i.e. they call functions or send Ether)
// into three phases:
// 1. checking conditions
// 2. performing actions (potentially changing conditions)
// 3. interacting with other contracts
// If these phases are mixed up, the other contract could call
// back into the current contract and modify the state or cause
// effects (ether payout) to be performed multiple times.
// If functions called internally include interaction with external
// contracts, they also have to be considered interaction with
// external contracts.
// 1. Conditions
require(now >= auctionEnd, "Auction not yet ended.");
require(!ended, "auctionEnd has already been called.");
// 2. Effects
ended = true;
emit AuctionEnded(highestBidder, highestBid);
// 3. Interaction
beneficiary.transfer(highestBid);
}
}
When I call auction.auctionEnd() before the 300 seconds, I get an exception "Auction not yet ended", which is what it is supposed to do:
truffle(development)> auction.auctionEnd()
Error: VM Exception while processing transaction: revert Auction not yet ended.
at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)
at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1)
at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:64:1)
at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/httpprovider.js:128:1)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-provider/wrapper.js:134:1
at /usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/requestmanager.js:86:1
at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:38:1)
When I call it after 300 seconds, I get a transaction and an event AuctionEnded, so it looks like the now >= auctionEnd condition is met:
truffle(development)> auction.auctionEnd()
{ tx: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
receipt:
{ transactionHash: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
transactionIndex: 0,
blockHash: '0xfde6956d9c7d6e99235606b70e11161965ddf832063e572a87df00c14484e5a1',
blockNumber: 12,
gasUsed: 76921,
cumulativeGasUsed: 76921,
contractAddress: null,
logs: [ [Object] ],
status: '0x1',
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000040000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
logs:
[ { logIndex: 0,
transactionIndex: 0,
transactionHash: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
blockHash: '0xfde6956d9c7d6e99235606b70e11161965ddf832063e572a87df00c14484e5a1',
blockNumber: 12,
address: '0xef0a6e95779240516e8a05039f97968f727c4f18',
type: 'mined',
event: 'AuctionEnded',
args: [Object] } ] }
Hopefully this can help you. I think you missed time travel part.
// test/SimpleAuction.js
const sa = artifacts.require("SimpleAuction");
contract('SimpleAuction', async function(accounts) {
/**
* TimeTravel function - can move this to helper file
* https://www.reddit.com/r/ethdev/comments/6n65ar/using_testrpc_and_truffles_built_in_js_tests_how/dk7357l/
*/
const timeTravel = function (time) {
return new Promise((resolve, reject) => {
web3.currentProvider.sendAsync({
jsonrpc: "2.0",
method: "evm_increaseTime",
params: [time], // 86400 is num seconds in day
id: new Date().getTime()
}, (err, result) => {
if(err){ return reject(err) }
return resolve(result)
});
})
}
var sa_instance;
var highest_bid = 2; // ether
var bob = accounts[1];
var alice = accounts[2];
var john = accounts[3];
var beneficiary = accounts[accounts.length - 1]; // last account in Ganache
var beneficiary_initial_balance;
before(async function() {
sa_instance = await sa.new(300, beneficiary);
var bib_balance_wei = await web3.eth.getBalance(beneficiary);
var bib_balance_eth = web3.fromWei(web3.toDecimal(bib_balance_wei), "ether");
beneficiary_initial_balance = parseInt(bib_balance_eth);
})
it("Bob bids with 1 ETH", async function() {
await sa_instance.bid({from: bob, value: web3.toWei(1, "ether")})
var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
assert.equal(sa_balance_eth, 1);
})
it("Alice bids with 2 ETH", async function() {
await sa_instance.bid({from: alice, value: web3.toWei(highest_bid, "ether")})
var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
assert.equal(sa_balance_eth, 3);
})
it("Bob can withdraw his 1 ETH back", async function() {
await sa_instance.withdraw({from: bob})
var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
assert.equal(sa_balance_eth, highest_bid);
})
it("Anyone can end the auction when it's due", async function() {
await timeTravel(300);
await sa_instance.auctionEnd({from: john});
})
it("Contract balance left with 0 ETH", async function() {
var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
assert.equal(sa_balance_eth, 0);
})
it("And beneficiary is now 2 ETH richer", async function() {
var bib_balance_wei = await web3.eth.getBalance(beneficiary);
var bib_balance_eth = web3.fromWei(web3.toDecimal(bib_balance_wei), "ether");
var expected_new_beneficiary_balance = beneficiary_initial_balance + highest_bid;
assert.equal(expected_new_beneficiary_balance, bib_balance_eth);
})
})
Did auctionEnd() succeed?
Most likely require(now >= auctionEnd) is not satisfied thus auctionEnd() failed.
Update: Debugged the contract myself, the transfer is successful. Beneficiary address is: 0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286 not account1. So the contract works as expected, there is no problem. Check the balance of beneficiary address, you will see it has 15 ether.
Clarification:
This is the deployment instruction:
module.exports = function(deployer) {
deployer.deploy(SimpleAuction, 300, "0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286");
};
So you set beneficiary address as: 0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286.
And this is the transfer instruction inside auctionEnd():
beneficiary.transfer(highestBid);
So after the execution, if you run the following command you will see that beneficiary has 15 ether.
web3.eth.getBalance("0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286")
BigNumber { s: 1, e: 19, c: [ 150000 ] }

How can I re create raw transaction from the transaction receipt to verify v,r,s signature?

I'm trying to verify Ethereum transaction.
Here's my steps.
1. make a transaction
2. get transaction with eth.getTransaction()
3. re-create transaction with ethereumjs-tx
But sometimes I can not verify transaction.
Case 1: simple send ether transaction on private test net
get a transaction detail
{
blockHash: "0x2125539ac67b4569828737ffb1731048e00121954f0555d0dc96af665071a62b",
blockNumber: 24615,
from: "0x81c24515cdf1a4b68f34e3e2824d44b28d00f010",
gas: 90000,
gasPrice: 18000000000,
hash: "0x9e4ce952759eae925173c6c6055c1afe577a48462caacd8d4fb742e911eae053",
input: "0x",
nonce: 0,
r: "0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093",
s: "0x2a87e18b22c76d61ce9d6a4d56949afa025f1611aa6bb9fd9d6c502d61f7361b",
to: "0x487f5eea74ea5f3e94093d8b0501f1d2b0d5310a",
transactionIndex: 0,
v: "0x10f469",
value: 1000000000000000000
}
then create a transactin with the transaction detail and ethereumjs-tx.
const EthereumTx = require('ethereumjs-tx')
const test_arr1 = {
nounce: "0x"+parseInt(0, 10).toString(16),
gasPrice: "0x"+parseInt(18000000000, 10).toString(16),
gasLimit: "0x"+parseInt(90000, 10).toString(16),
to: '0x487f5eea74ea5f3e94093d8b0501f1d2b0d5310a',
value: "0x"+parseInt(1000000000000000000, 10).toString(16),
data: '0x',
v: '0x10f469',
r: '0x826b5348acbec72bab39c5debc8493e34d23b351bc7c20ded25d2a4eed736093',
s: '0x2a87e18b22c76d61ce9d6a4d56949afa025f1611aa6bb9fd9d6c502d61f7361b'
}
const tx = new EthereumTx(test_arr1);
const recoveredAddress = "0x"+tx.getSenderAddress().toString('hex')
recoveredAddress is 0x81c24515cdf1a4b68f34e3e2824d44b28d00f010 which is correct
Case 2: smart contract in ropsten testnet
get a transaction detail
{
blockHash: "0xead9335751dbdb4a874b2bb48ac15ddafbec6f2ba55a5932bf6ec1a0475166e7",
blockNumber: 3026266,
from: "0x0d6883a0e7071513c7d90a27bf2715bc71ecf107",
gas: 309588,
gasPrice: 18000000000,
hash: "0xe69d8b108af59198857dd5b045769748dbe1ca3ad9bba7dbbb512643b9d85b5a",
input: "0x03e63bdb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000890000000b000000012e507fe5cce2f11c2a520a265f593c08372834fec925f84bbe5a72793ec5096d03fd11970afed8b767adfed60caf3f0c1de0dbda06d48f9afc3661717dbf85641b3f011114d3a41bf16a8d8cc33769aba2abe14efb14487295c80da13b3e333707202d1bdea56f75616202491b4bcc437b6a5b7a79284a08e28bcd0a90e3d87bf10000000000000000000000000000000000000000000000",
nonce: 129,
r: "0xdd4fe550275bd35ffd4babf6ac3578575594011f027923046da78a7b179ffb66",
s: "0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b",
to: "0xad5e2d5cb93f098423597c891d2f1ed35f904ca1",
transactionIndex: 0,
v: "0x2a",
value: 0
}
then create a transactin with the transaction detail and ethereumjs-tx.
const EthereumTx = require('ethereumjs-tx')
const test_arr2 = {
nounce: "0x"+parseInt(129, 10).toString(16),
gasPrice: "0x"+parseInt(18000000000, 10).toString(16),
gasLimit: "0x"+parseInt(309588, 10).toString(16),
to: '0xad5e2d5cb93f098423597c891d2f1ed35f904ca1',
value: "0x",
data: '0x03e63bdb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000890000000b000000012e507fe5cce2f11c2a520a265f593c08372834fec925f84bbe5a72793ec5096d03fd11970afed8b767adfed60caf3f0c1de0dbda06d48f9afc3661717dbf85641b3f011114d3a41bf16a8d8cc33769aba2abe14efb14487295c80da13b3e333707202d1bdea56f75616202491b4bcc437b6a5b7a79284a08e28bcd0a90e3d87bf10000000000000000000000000000000000000000000000',
v: '0x2a',
r: '0xdd4fe550275bd35ffd4babf6ac3578575594011f027923046da78a7b179ffb66',
s: '0x2584e1f3f36185f6cd9358146f2479dde41dbb85ced5859c845a065cb5bdc42b',
chainId: 3
}
const tx2 = new EthereumTx(test_arr2);
const recoveredAddress = "0x"+tx2.getSenderAddress().toString('hex')
recoveredAddress is 0x9c9d4315824275f545b2e96026a7075f75125b9b which is NOT correct. It should be 0x0d6883a0e7071513c7d90a27bf2715bc71ecf107
Why is that?
How can I re-create raw transaction correctly?
Or is there any other way to verify transaction with v,r,s signature?
Thanks in advance.
If you're using web3js v1.0, you can simply use web3.eth.accounts.recover. Example from their documentation:
web3.eth.accounts.recover({
messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655',
v: '0x1c',
r: '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd',
s: '0x6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029'
})
> "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"
Another option is you can call a view function in a contract that uses Solidity's ecrecover(). From the Solidity docs:
ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address): recover address associated with the public key from elliptic curve signature, return zero on error
Example:
function verify(bytes prefix, bytes32 msgHash, uint8 v, bytes32 r, bytes32 s) external pure returns(address) {
bytes32 prefixedHash = keccak256(prefix, msgHash);
return ecrecover(prefixedHash, v, r, s);
}
You have to be careful with the prefix though. Different clients may use a different prefix. For example, geth signs transactions with prefix = "\x19Ethereum Signed Message:\n32".