I don't know why the transfer function does not work.
I try npx hardhat test but it seems to fail when transferring.
function deposit(address token, uint256 amount) external onlyOwner {
uint256 balance = ERC20(token).balanceOf(msg.sender);
require(balance > amount, "not enough money to deposit");
ERC20(token).approve(address(this), amount);
ERC20(token).transferFrom(msg.sender, address(this), amount);
}
This is the hardhat js code which executes the contract
let IWETH = await ethers.getContractAt(
"IWETH",
"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
);
await IWETH.deposit({
value: ethers.utils.parseUnits("100.0", "ether"),
});
await contract
.connect(owner)
.deposit(
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
ethers.utils.parseUnits("2", "ether")
);
I seems like it failed at ERC20(token).transferFrom(msg.sender, address(this), amount);
Related
I've created a simple Contract extending openzeppelin ERC20.
I'm trying to transfer token from one address to another.
Contract code is as below:
File name: Token.sol
pragma solidity ^0.7.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
uint256 public INITIAL_SUPPLY = 100000;
constructor() ERC20("My Token", "MYT") {
_mint(msg.sender, INITIAL_SUPPLY);
}
}
Code within test file:
const { expect } = require("chai");
describe("Send token from second address in the block", function () {
it("Send 100 MYT to the third account", async function () {
const Token = await ethers.getContractFactory("Token");
const token = await Token.deploy();
// get accounts from the network
const [owner, secondAccount, thirdAccount] = await ethers.getSigners();
// send some credit to the second account
await token.transfer(secondAccount.address, 500);
// Approve token transfer
await token.approve(secondAccount.address, 200);
// Transfer credit from second account to the third account (This step is not working)
await token.transferFrom(secondAccount.address, thirdAccount.address, 100);
});
});
Error received:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds allowance'
at Token.sub (#openzeppelin/contracts/math/SafeMath.sol:171)
at Token.transferFrom (#openzeppelin/contracts/token/ERC20/ERC20.sol:154)
at processTicksAndRejections (internal/process/task_queues.js:94:5)
at runNextTicks (internal/process/task_queues.js:63:3)
at listOnTimeout (internal/timers.js:501:9)
at processTimers (internal/timers.js:475:7)
at EthModule._estimateGasAction (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:421:9)
at HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:105:18)
at EthersProviderWrapper.send (node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
Thank you for the help.
If you check Approve if erc20, the function arguments expect address _spender, uint256 _value as arguments. In your case you approved secondAccount to withdraw 200 tokens.
It means secondAccount can transfer those token to his account from the token contract. To do that, you try await token.connect(secondAccount).transferFrom(token.address,secondAccount.address,100);
I am working on a simple bank smart contract example but I am having trouble getting the contract to restrict a sender from withdrawing more than the remaining balance. Here is my function within the contract:
function withdraw(uint withdrawAmount) public returns (uint) {
assert(balances[msg.sender] >= withdrawAmount);
balances[owner] -= withdrawAmount;
emit LogWithdrawal(msg.sender, withdrawAmount, balances[msg.sender]);
return balances[msg.sender];
}
Here is the .js test:
it("should not be able to withdraw more than has been deposited", async() => {
await instance.enroll({from: alice})
await instance.deposit({from: alice, value: deposit})
await catchRevert(instance.withdraw(deposit + 1, {from: alice}))
})
I was thinking maybe assert(.....) but that didn't work so any assistance would be appreciated.
First of all, you should use require instead of assert in this case. That being said your code seems ok, so make sure you are keeping track of the user balances correctly.
Your code is not consistent, you check the balance for msg.sender, but withdraw from owner.
It should be the correct version:
function withdraw(uint withdrawAmount) public returns (uint) {
require(balances[msg.sender] >= withdrawAmount);
balances[msg.sender] -= withdrawAmount;
emit LogWithdrawal(msg.sender, withdrawAmount, balances[msg.sender]);
return balances[msg.sender];
}
I would like to use delegatecall to deposit ETH into WETH and batch this process together with other actions (see code below). When running truffle tests, it seems like the events are triggered correctly but the state does not seem to be updated.
Same behavior on the Rinkeby network. The weird thing is that the transaction completes completely successfully. Here is an example of transaction: https://rinkeby.etherscan.io/tx/0x93c724174e2b70f2257544ebc0e0b9da6e31a7a752872da7683711bd4d4bd92b
Solidity code:
pragma solidity 0.4.24;
import "../interfaces/ERC20.sol";
import "./WETH9.sol";
contract SetupAccount {
address public exchangeAddress;
address public wethAddress;
constructor (
address _exchangeAddress,
address _wethAddress
) public {
exchangeAddress = _exchangeAddress;
wethAddress = _wethAddress;
}
function setup(
address[] _tokenAddresses,
uint256[] _values
) public payable {
for (uint i = 0; i < _tokenAddresses.length; i++) {
_tokenAddresses[i].delegatecall(abi.encodeWithSignature("approve(address,uint256)", exchangeAddress, _values[i]));
}
if (msg.value != 0) {
wethAddress.delegatecall(abi.encodeWithSignature("deposit()"));
}
}
Failing truffle test:
describe('setupAccount', async () => {
beforeEach(async () => {
weth = await WETH.new()
exchange = await Exchange.new(rewardAccount)
bnb = await BNB.new(user1, 1000)
dai = await DAI.new(user1, 1000)
omg = await OMG.new(user1, 1000)
setupAccount = await SetupAccount.new(exchange.address, weth.address)
})
it('setupAccount should deposit weth and approve tokens', async () => {
await setupAccount.setup(
[bnb.address, dai.address, omg.address],
[1000, 1000, 1000],
{ from: user1, value: 10 ** 18 }
)
let wethBalance = await weth.balanceOf(user1)
wethBalance.should.be.bignumber.equal(10 ** 18)
bnbAllowance.should.be.bignumber.equal(1000)
daiAllowance.should.be.bignumber.equal(1000)
omgAllowance.should.be.bignumber.equal(1000)
})
})
Events emitted during test:
Events emitted during test:
---------------------------
Deposit(dst: <indexed>, wad: 1000000000000000000)
---------------------------
Test result:
1) Contract: SetupAccount
setupAccount
setupAccount should deposit weth and approve tokens:
AssertionError: expected '0' to equal '1000000000000000000'
+ expected - actual
-0
+1000000000000000000
I'm confused as to why this doesn't work. Thank's in advance.
msg.value is preserved correctly through a delegatecall. The following code demonstrates this, as evidenced by the emitted event showing the correct value.
pragma solidity >0.4.99 <0.6;
contract Target {
event Received(uint256 amount);
function deposit() external payable {
emit Received(msg.value);
}
}
contract Delegater {
function deposit() external payable {
(bool success,) = address(new Target()).delegatecall(abi.encodeWithSignature("deposit()"));
require(success);
}
}
I'm trying to get the balance of an address on my smart contract using web3, but the balance is always 0. Using metamask on Rinkeby since my contract is deployed on rinkeby. https://rinkeby.etherscan.io/address/0x8e3a88be716ce7c8119c36558ec97bc634592255
You can verify the wallet has a balance by putting it in the balanceOf function on etherScan. Use the address 0x8b54A82a12bD5A7bA33B4842cA677E55f78a8612
let provider = web3.currentProvider;
web3 = new Web3(provider);
let abi = 'too long of a string to post here';
let MyContract = web3.eth.contract(JSON.parse(abi));
let myContractInstance = MyContract.at('0x8e3a88be716ce7c8119c36558ec97bc634592255');
let address = '0x8b54A82a12bD5A7bA33B4842cA677E55f78a8612';
function balanceOf(address) {
if (!address) {
return;
}
this.myContractInstance.balanceOf.call(address, function(error, balance) {
if (error) {
return;
}
alert(balance.c[0] + ' RHC');
});
}
balanceOf(address);
Here is the getBalance function on my contract
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
Website implemented on http://robinhoodcoin.net/metamask.html
Code https://github.com/robinhoodcoin/robinhoodcoin.github.io/blob/master/metamask.html
EDIT
when I change the provider to be the following:
var web3 = new Web3(new Web3.providers.HttpProvider('https://rinkeby.infura.io/'));
I am able to get the balance. SO there is something up with using metamask as the provider.
The line at https://github.com/robinhoodcoin/robinhoodcoin.github.io/blob/master/metamask.html#L118 has a typo. It reads:
self.myContractInstance = self.MyContract.at(self.address);
but the address is stored at self.contractAddress, so it should read:
self.myContractInstance = self.MyContract.at(self.contractAddress);
After making that fix, the page works fine for me with MetaMask.
I was reading the IBM Example about smartSponsor, and there is this following code:
personal.unlockAccount(thesponsor,"password");
ss.pledge("Good luck with the run!", {from: thesponsor, value: 10000000, gas: 3000000});
While the function pledge is:
function pledge(bytes32 _message) {
if (msg.value == 0 || complete || refunded) throw;
pledges[numPledges] = Pledge(msg.value, msg.sender, _message);
numPledges++;
}
struct Pledge {
uint amount;
address eth_address;
bytes32 message;
}
I was looking for "send" or "transfer" functions. But I could not find any. Therefore I was confused how were the ethers sent from the sponsor to the smart contract?
Update:
How did the sender send the ethers? I was expecting something like .transfer(uint256 amount) or .send(uint256 amount). But it seems that there is no such function call?
They are in magical variable msg. The function pledge uses this variable in the following line:
pledges[numPledges] = Pledge(msg.value, msg.sender, _message);