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

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 ] }

Related

How to concatenate 2 String in Solidity and encode Keccak256?

i'm working at a smart-contract that has a merkle-tree function in it.
Basically i'm passing the proof from a firebase function that take in input the address and the n° of token reserved by the user, and gives as output the proof to the front-end that execute the smart-contract function.
The only thing i need to figure out is the leaf calculation, on the firebase function it is composed by encoding keccak256 the string in the array, composed by an eth address concatenated with the number of reserved tokens (0x38207d0e84edb04a57482c3769fe192617520373 + 3), in the smart contract instead, the leaf is calculated with the keccak256(abi.encodepacked(0x38207d0e84edb04a57482c3769fe1926175203733, 3), and it's not passing the verifiy...
I think these two methods of calculation are different in some part, can you help me?
I'm going to paste the code of both functions:
SOLIDITY
// 1. Address check, if the proof is valid
function isPrivateListed(
uint256 _addressReservedTokens,
bytes32[] memory _proof
) public view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, _addressReservedTokens);
return MerkleProof.verify(_proof, privateListRoot, leaf);
}
// 2. Mint function called from the front-end
function privateMint(
uint256 _mintAmount,
uint256 _addressReservedTokens,
bytes32[] calldata proof
) public payable {
require(privateOpen, "The private mint is not opened");
require(
isPrivateListed(_addressReservedTokens, proof),
"you are not in the private list"
);
uint256 supply = totalSupply();
require(supply + _mintAmount <= maxSupply, "max NFT limit exceeded");
uint256 owned = addressMintedBalance[msg.sender];
require(
owned + _mintAmount <= _addressReservedTokens,
"You have less nft reserved"
);
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(msg.sender, supply + i);
addressMintedBalance[msg.sender]++;
}
}
FIREBASE FUNCTION
// 1. Get parameters from the function called from client side
const walletAddress = data.walletAddress;
let whitelistAddresses = [
'0x38207d0e84edb04a57482c3769fe1926175203733',
'0x943926a8ff0000350d0b879a658fa52bcd4fca186',
];
// 2. Create a new array of `leafNodes` by hashing all indexes of the `whitelistAddresses`
// using `keccak256`. Then creates a Merkle Tree object using keccak256 as the algorithm.
const leafNodes = whitelistAddresses.map((addr) => keccak256(addr));
const merkleTree = new MerkleTree(leafNodes, keccak256, {
sortPairs: true,
});
// 3. Get root hash of the `merkleeTree` in hexadecimal format (0x)
const rootHash = merkleTree.getRoot();
const rootHashHex = merkleTree.getHexRoot();
// ***** ***** ***** CLIENT-SIDE ***** ***** ***** //
const claimingAddress = keccak256(walletAddress);
const hexProof = merkleTree.getHexProof(claimingAddress);
const verifyProof = merkleTree.verify(hexProof, claimingAddress, rootHash);
In solidity you're hashing a (20+32)-bytes element
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, _addressReservedTokens);
Since msg.sender is 20 bytes and _addressReservedTokens is 32 bytes, the output of abi.encodePacked() is something like this:
0x38207d0e84edb04a57482c3769fe1926175203730000000000000000000000000000000000000000000000000000000000000003
This is clearly different than 0x38207d0e84edb04a57482c3769fe1926175203733 used by firebase.
Also I'm not sure if the js keccak256 is interpreting that value as string or as bytes (in solidity it's bytes).
The best fix is probably changing the js code. You can write the correct whitelistAddresses using ethers, see here https://ethereum.stackexchange.com/questions/119990/how-to-mimic-abi-encodepacked-in-ethers

How to call contract method and send value with it in web3Provider?

I'm using walletconnect/metamask as wallets, and web3Provider as provider for my "buy tokens" function.
I'm trying to use the populateTransaction.METHOD_NAME to make a transaction from my wallet to the contracts method (with BNB transfer).
I'm trying to transfer some BNB's to contract with calling the contracts "BuyTokensForBnb" function (Like we can do it with Remix IDE.)
But I keep running into errors :/
const purchaseTokens2 = async () => {
const HODLER = await new ethers.Contract(address, abi, web3providerState);
const tx = [{
nonce: "0x00", // ignored by MetaMask
to: HODLER.address, // Required except during contract publications. (LINK CONTRACT ADDRESS MAINNET/TESTNET)
value: "0xde0b6b3a7640000", // Only required to send ether to the recipient from the initiating external account.
data: '',
// Optional, but used for defining smart contract creation and interaction.
chainId: "0x61" // Used to prevent transaction reuse across blockchains. Auto filled by MetaMask.
}];
let resp = HODLER.populateTransaction.buyTokensForBnb(0, tx)
const signer = await web3providerState.getSigner();
console.log("Non signer", web3providerState);
console.log("Signer, ", signer);
console.log("Account:", await signer.getAddress());
let tx2 = await signer.sendTransaction(tx);
let signature = await signer.signMessage("Hello world");
console.log(tx2, signature);
}
BuyTokensForBnb function
function buyTokensForBnb() public payable {
require(msg.value > minbuy, "MINIMUM PURCHASE IS 0.01 BNB");
require(msg.value <= maxbuy, "MAX BUY IS 10 BNB");
require(getPresaleState() == 5 || getPresaleState() == 4, "PRESALE IS NOT RUNNING(COULD BE CANCELLED OR ENDED, OR FINALIZED)");
if(block.timestamp > endDate || block.timestamp < startDate) {
revert("You can't buy this token yet or Presale had already ended, tokens cannot be purchased any longer.");
} else {
if(getPresaleState() == 4) {
//WHITELISTED PRESALE
PresaleWallet storage presaleWallet = presaleWallets[msg.sender];
if(presaleWallet.whitelisted == false) {
if(block.timestamp >= whitelistedEndDate) {
presaleState = PresaleState.LIVE;
generateReceiptAndUserPurchasedTokens(msg.sender, msg.value);
} else {
revert('REFUNDED, YOUR WALLET IS NOT WHITELISTED');
}
} else {
//make purchase, update tokens.
generateReceiptAndUserPurchasedTokens(msg.sender, msg.value);
}
} else if(getPresaleState() == 5) {
generateReceiptAndUserPurchasedTokens(msg.sender, msg.value);
} else {
revert('REFUNDED, PRESALE IS NOT LIVE OR IN WHITELISTED MODE');
}
}
}

Ethereum transaction giving error 'invalid sender'

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
};

waitOnReceipt function doesn't work in solidity, running on SuperBlocks

Running on https://studio.superblocks.com/ trying to make a a fun game in Solidity. the problem happens when I call waitfor receipt inside the "addKity" function. Any ideas why? I suspect it could be because of a technical issue in superblocks but could very well be because of a coding error I have.
It reaches the "heres" alert but doesn't reach alert("4");
Please let me know your thoughts!
waitForReceipt(txHash, function(receipt){
Javascript File
(function (Contract) {
var web3_instance;
var instance;
var accounts;
function init(cb) {
web3_instance = new Web3(
(window.web3 && window.web3.currentProvider) ||
new Web3.providers.HttpProvider(Contract.endpoint));
accounts = web3.eth.accounts;
var contract_interface = web3_instance.eth.contract(Contract.abi);
instance = contract_interface.at(Contract.address);
cb();
}
function waitForReceipt(hash, cb) {
web3.eth.getTransactionReceipt(hash, function (err, receipt) {
if (err) {
error(err);
}
if (receipt !== null) {
// Transaction went through
if (cb) {
cb(receipt);
}
} else {
// Try again in 1 second
window.setTimeout(function () {
waitForReceipt(hash, cb);
}, 1000);
}
});
}
function addKitty(){
// var KittyName = "he"; //$("#kittyName").val();
// var KittyPrice = 5;//parseInt($("#kittyPrice").val());
const transactionObject = {
from: "0x95c2332b26bb22153a689ae619d81a6c59e0a804",
gas: "1000000",
gasPrice: "1000000",
value:"1000"
};
instance.addNewKitty.sendTransaction("sdad",5, transactionObject, (error, result) => {
if(error){
alert(error);
alert("2");
}
else{
alert("heres");
waitForReceipt(txHash, function(receipt){
alert("4");
// if(receipt.status === "0x1"){
// alert("got receipt");
// }
// else{
// alert("5");
// alert("receipt status fail");
// }
});
}
})
}
// function getMessage(cb) {
// instance.message(function (error, result) {
// cb(error, result);
// });
// }
$(document).ready(function () {
init(function () {
// getMessage(function (error, result) {
// if (error) {
// console.error("Could not get article:", error);
// return;
// }
// $('#message').append(result);
// });
$("#addKitty").click(function(){
addKitty();
})
});
});
})(Contracts['CryptoKitties']);
Solidity file
pragma solidity ^0.4.21;
contract CryptoKitties {
address public owner;
struct CKitties{
string name;
uint price;
}
function CryptoKitties() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
mapping (address => uint) kittytoUser;
CKitties[] kitties;
event NewCryptoKitty(address owner, string name, uint price);
modifier cost (uint minCost){
require(msg.value>= minCost && minCost >=0);
_;
}
function addNewKitty(string newName, uint newPrice) public payable cost(5000) {
address sender = msg.sender;
uint place = kitties.push(CKitties(newName,newPrice));
kittytoUser[sender] = place;
emit NewCryptoKitty(sender, newName, newPrice);
}
function kill() public onlyOwner{
selfdestruct(owner);
}
function getName() public view returns (string){
address sender = msg.sender;
uint index = kittytoUser[sender]-1;
return kitties[index].name;
}
function setName(string newName) public{
address sender = msg.sender;
uint index = kittytoUser[sender]-1;
kitties[index].name = newName;
}
function getBalance() public view returns (uint){
return address(this).balance;
}
}
First, the waitForReceipt function is getting called passing an undefined value txHash. In that context, it should be result instead (the value coming from the callback that activated that call, triggered by sendTransaction).
That change will make waitForReceipt call work.
The other problem is that you have the web3 variable named as web3_instance, but you still refer to it as web3.
Considering that, inside waitForReceipt, you are still referencing to it as web3.eth..., while the correct call in that context would be: web3_instance.eth.getTransactionReceipt....
With that fixed, alert("4") will get called as intended.

Why does the value of a mapping(bytes32 => uint8) seem to change between transaction calls?

The contract code:
pragma solidity ^0.4.10;
contract Test {
mapping (bytes32 => uint8) private dict;
function Test() {}
function Set(bytes32 key, uint8 val) returns (uint8) {
dict[key] = val;
return dict[key];
}
function Get(bytes32 key) returns (uint8) {
return dict[key];
}
}
and I run on testrpc:
contract_file = 'test/test.sol'
contract_name = ':Test'
Solc = require('solc')
Web3 = require('web3')
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
source_code = fs.readFileSync(contract_file).toString()
compiledContract = Solc.compile(source_code)
abi = compiledContract.contracts[contract_name].interface
bytecode = compiledContract.contracts[contract_name].bytecode;
ContractClass = web3.eth.contract(JSON.parse(abi))
contract_init_data = {
data: bytecode,
from: web3.eth.accounts[0],
gas: 1000000,
}
deployed_contract = ContractClass.new(contract_init_data)
deployed_contract.Set.call("akey", 5)
deployed_contract.Get.call("akey")
bizarrely, this is the output I get in the node terminal:
> deployed_contract.Set.call("akey", 5)
{ [String: '5'] s: 1, e: 0, c: [ 5 ] }
> deployed_contract.Get.call("akey")
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
This result is the outcome of a long debugging session... what is going on? It seems distinctly like something is broken here, but I followed a tutorial which did something very similar which seems to work...
also:
> Solc.version()
'0.4.11+commit.68ef5810.Emscripten.clang'
Try this deployed_contract.Set("akey", 5) without .call
Because .call on your setter method
executes a message call transaction, which is directly executed in the
VM of the node, but never mined into the blockchain.
doc
The value of the map does not change. I bet 0 is the default value when nothing is set
By the way try using the online compiler you will quickly see if the problem is on the contract or the way you interact with it with web3.