Thank you @abcoathup.
Could you have a look into this error here? I redesign the contract to be upgradeable. The upgrade seems to work, as the balance is still there after the upgrade, but the contract will not let me withdraw the funds and will revert when calling the withdraw function.
Also, when interacting from the console, I did following your advice from the previous post, I get:
withdraw is not a function
. Is it because of the Instanbul fork? But I don't quite understand why, as I try to withdraw funds to a user account, and @nventuro states here that
Note that sending funds from external accounts, or from other contracts via either
payable
functions orcall
will continue to work correctly.
I just also tried to change transfer() to call() using this approach:
function withdraw(uint256 amount) external onlyOwner {
require(
amount <= address(this).balance,
"Requested amount is higher than currently deposited value"
);
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed.");
emit Withdrawn(msg.sender, amount);
}
...but no luck, still reverts.
Or is it because the call is sent from the proxy to the implementation?
errorMessage
'0x223fc5929eb1ca408838ed3b3306706063e3d47779d3561d29233a9368deb013': { error: 'revert', program_counter: 1123, return: '0x' },
stack: 'RuntimeError: VM Exception while processing transaction: revert\n' +
' at Function.RuntimeError.fromResults (C:\\Users\\sound\\AppData\\Local\\Programs\\Ganache\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n' +
' at BlockchainDouble.processBlock (C:\\Users\\sound\\AppData\\Local\\Programs\\Ganache\\resources\\static\\node\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:24)\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:93:5)',
name: 'RuntimeError'
}
√ should allow owner to withdraw (196ms)
contract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../node_modules/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract MOTDTreasury is OwnableUpgradeable{
event Paid(address from, uint256 amount);
event Withdrawn(address by, uint256 amount);
function initialize() public initializer {
__Ownable_init();
}
receive() external payable {
emit Paid(msg.sender, msg.value);
}
/**
* @notice Withdraws some funds from this contracy
* @param amount the amount of funds to winthdraw
*/
//THIS FUNCTION REVERTS IN UNIT TEST, ALSO IN CONSOLE
function withdraw(uint256 amount) external onlyOwner {
require(
amount <= address(this).balance,
"Requested amount is higher than currently deposited value"
);
payable(msg.sender).transfer(amount);
emit Withdrawn(msg.sender, amount);
}
}
test.js
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');
const { assert } = require('chai');
const truffleAssert = require('truffle-assertions');
const Treasury = artifacts.require('MOTDTreasury');
const Treasury2 = artifacts.require('MOTDTreasuryV2');
const Web3 = require("web3");
let web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545")); //
contract('Treasury (proxy)', async function (accounts) {
it('should deploy proxy and set owner to accounts[0]', async function () {
console.log("Deploying Proxy...");
this.treasury1 = await deployProxy(Treasury, {initializer: 'initialize'});
console.log("Treasury1 Proxy Address: " + this.treasury1.address);
let owner = await this.treasury1.owner();
console.log("Owner is: " + owner);
assert.equal(owner, accounts[0]);
});
it('should allow to deposit ETH', async function() {
let treasBalance = await web3.eth.getBalance(this.treasury1.address);
console.log("Balance Treasury1 BEFORE TX: " + treasBalance);
acc1Balance = await web3.eth.getBalance(accounts[1]);
console.log("Balance accounts[1] BEFORE TX: " + acc1Balance);
console.log("Sending Ether from accounts[1] to treasury");
await web3.eth.sendTransaction({
from: accounts[1],
to: this.treasury1.address,
value: web3.utils.toWei("2", "ether"),
});
console.log("New Balance accounts[1]: " + await web3.eth.getBalance(accounts[1]));
});
it('stores Eth', async function () {
let treasuryBalance = await web3.eth.getBalance(this.treasury1.address);
console.log("Treasury1 Balance: " + treasuryBalance);
});
it('should revert if withdraw by not owner!', async function () {
let treasuryBalance = await web3.eth.getBalance(this.treasury1.address);
console.log("Balance Treasury1 BEFORE withdraw: " + treasuryBalance);
try {
await this.treasury1.withdraw(web3.utils.toWei("1", "ether"), {from: accounts[1]});
} catch(err){
console.log(err.reason);
}
console.log("Balance should stay the same");
console.log("Balance Treasury AFTER: " + treasuryBalance);
});
it('should revert if withdraw amount is too high', async function () {
let treasuryBalance = await web3.eth.getBalance(this.treasury1.address);
console.log("Balance Treasury BEFORE: " + treasuryBalance);
try {
await this.treasury1.withdraw(web3.utils.toWei("5", "ether"), {from: accounts[0]});
}
catch (err2){
console.log("Err2" + err2);
}
console.log("Balance should stay the same");
console.log("Balance Treasury1 AFTER: " + treasuryBalance);
});
it('should keep balance after proxy upgrade', async function () {
console.log("Upgrading Proxy...");
this.treasury2 = await upgradeProxy(this.treasury1.address, Treasury2, {initializer: 'initialize'});
console.log(await this.treasury2.sayHello());
console.log("Treasury2 Address: " + this.treasury2.address);
owner = await this.treasury2.owner();
console.log("Owner is: " + owner);
console.log("Balance should still be 1 ETH:");
console.log("Treasury2 Balance: " + await web3.eth.getBalance(this.treasury2.address));
})
//THIS ONE KEEPS REVERTING
it('should allow owner to withdraw', async function () {
// console.log(await web3.eth.getBalance(this.treasury2.address));
// truffleAssert.passes(
// await this.treasury2.withdraw(web3.utils.toWei("1", "ether"), {from: owner})
// )
// console.log(await web3.eth.getBalance(this.treasury2.address));
let tresInst = await Treasury2.at(this.treasury2.address);
try{
await tresInst.withdraw(web3.utils.toWei("1", "ether"), {from: accounts[0]});
} catch(err){
console.log(err.data);
}
})
})