I am working on a private development network set up with geth with PoA consensus. Everything is working well from the geth console. I have written a Solidity contract to initiate some ether transfers and I am calling methods from my JavaScript code using web3js and it is all working well.
My question is about a specific use case where I am trying to transfer ether from one EOA to another EOA by calling a contract method. Let me refer to three addresses, the first two are EOAs: <sender_address>
,<beneficiary_address>
and the third is what shows as the contract address when I deploy the contract <contract_address>
. When I deploy the contract (using truffle) , the account shown in the deployment summary is <sender_address>
.
The relevant snippets of code are below:
In my .sol file:
function payBeneficiary(address payable beneficiary, uint256 amount) external payable{
beneficiary.transfer(amount);
//Or, since I also pass the same amount in msg.value
//beneficiary.transfer(msg.value);
}
Update: See the additional code below to include events as recommended by @goodvibrations. Also, it is now recommended to use address.call{}():
//Declare an event in the contract
event PaidBeneficiary(address indexed sender, address indexed beneficiary, uint256 indexed amount);
//Make the transfer call
(bool success, bytes memory response) = beneficiary.call{value: amount}("");
require(success, "Pay Beneficiary was not successful.");
//And emit the event on success
if(success){
emit PaidBeneficiary(msg.sender, beneficiary, amount);
}else{
//emit failure event maybe?
}
In my .js file where I use web3js:
var myContract = new web3.eth.Contract(myContract_abi, "<contract_address>");
myContract.methods.payBeneficiary(bene_address, amount_ether).send(
{
from: "<sender_address>",
value: web3.utils.toWei(amount_ether, "ether"),
}
)
.on('transactionHash', function(hash){
console.log(hash);
web3.eth.getTransaction(hash,(error, result) => {
if(error){console.log(error);}
else {console.log(result);}
})
})
.on('receipt', function(receipt){
})
.on('confirmation', function(confirmationNumber, receipt){
})
.on('error', function(error, receipt) {
if(error){console.log(error);}
else {console.log(receipt);}
});
Update: The JavaScript code needs to be updated as below to read the events.
//Listen for events
myContract.events.PaidBeneficiary({
filter: {},
fromBlock: 0
}, function(error, event){ console.log(event); })
.on('data', function(event){
console.log(event); // same results as the optional callback above
})
.on('changed', function(event){
// remove event from local database
})
.on('error', console.error);
My questions:
The contract method is getting executed and ether is being transferred from <sender_account>
to <beneficiary_account>
as expected. But, when I print the transaction object returned from the getTransaction method call passing the hash, I see from:<sender_address>
but to:<contract_address>
. The <contract_address>
balance is 0 and remains 0.
Is this the right approach and behaviour? If so, how do I track the transaction which will show me an ether transfer from <sender_account>
to <beneficiary_account>
?
And what is the difference between msg.value and the amount passed as a parameter to the method? Or can I only use msg.value and do not need the parameter?
msg.value
" - the correct approach is to get rid of theamount
parameter.