My delegatecall to call flow isn't completing the transaction and has no errors to show. is it a gas issue? (local harhdat)
I have the following:
contract TestRouter {
using SafeERC20 for IERC20;
constructor() {}
function deposit2(address asset, uint256 amount, address pool_, address caller) public {
(bool success, bytes memory result) = pool_.call(abi.encodeWithSignature("deposit(address,uint256,address,uint16)",asset,amount,caller,0));
console.log("deposit2", success);
}
contract TestRoutee {
using SafeERC20 for IERC20;
address public testRouter;
constructor(address _testRouter) {
testRouter = _testRouter;
}
function deposit(address asset, uint256 _amount, address pool_) public {
IERC20(asset).safeTransferFrom(msg.sender, address(this), _amount);
IERC20(asset).approve(pool_, _amount);
(bool success, bytes memory result) = testRouter.delegatecall(abi.encodeWithSignature("deposit2(address,uint256,address,address)",asset,_amount,pool_,address(this)));
}
}
The flow is user -> TestRoutee.deposit(...) -> TestRouter.deposit2(...) -> LendingPool.sol (AAVE V2)
This ends up going to another protocol called AAVE V2
The function calling in that protocol is:
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external override whenNotPaused {
DataTypes.ReserveData storage reserve = _reserves[asset];
console.log("deposit asset", asset);
console.log("deposit amount", amount);
console.log("deposit onBehalfOf", onBehalfOf);
console.log("deposit referralCode", referralCode);
console.log("deposit msg.sender", msg.sender);
ValidationLogic.validateDeposit(reserve, amount);
address aToken = reserve.aTokenAddress;
reserve.updateState();
reserve.updateInterestRates(asset, aToken, amount, 0);
IERC20(asset).safeTransferFrom(msg.sender, aToken, amount);
bool isFirstDeposit = IAToken(aToken).mint(onBehalfOf, amount, reserve.liquidityIndex);
if (isFirstDeposit) {
_usersConfig[onBehalfOf].setUsingAsCollateral(reserve.id, true);
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
}
emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode);
}
In that protocol, I deployed it locally and have it console.log'ing msg.sender and onBehalfOf correctly, that is it is showing the address of TestRoutee, which is what I want.
Although, it only gets up to console.log("deposit after safeTransferFrom");... Which is odd.
In there, the function is gets caught up on is the _mint function:
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), 'ERC20: mint to the zero address');
console.log("IncentivizedERC20 after require");
_beforeTokenTransfer(address(0), account, amount);
uint256 oldTotalSupply = _totalSupply;
_totalSupply = oldTotalSupply.add(amount);
uint256 oldAccountBalance = _balances[account];
console.log("IncentivizedERC20 _mint oldAccountBalance", oldAccountBalance);
_balances[account] = oldAccountBalance.add(amount);
console.log("IncentivizedERC20 _mint oldAccountBalance", oldAccountBalance);
if (address(_getIncentivesController()) != address(0)) {
_getIncentivesController().handleAction(account, oldTotalSupply, oldAccountBalance);
}
}
It console.log's up until console.log("IncentivizedERC20 _mint oldAccountBalance", oldAccountBalance);. Is it running out of gas or is there anohter issue here?
There shouldn't be any storage issues with the delegatecall, which is a usual concern but i pass all of the parameters to the TestRouter contract and it calls the LendingPool successfully.
Related
I've seen some problems with calling functions from other contracts but I believe my problem is fairly genuine to demand a separate question if only to be negated in its possibility.
So I am trying to call a contract within another contract. Is it possible to get the blockhash of a particular block number of the callee contract within my caller? If so how?
Every syntax I've attempted fails for some reason.
Contract A
enter code here
contract DiceGame {
uint256 public nonce = 0;
uint256 public prize = 0;
event Roll(address indexed player, uint256 roll);
event Winner(address winner, uint256 amount);
constructor() payable {
resetPrize();
}
function resetPrize() private {
prize = ((address(this).balance * 10) / 100);
}
function rollTheDice() public payable {
require(msg.value >= 0.002 ether, "Failed to send enough value");
bytes32 prevHash = blockhash(block.number - 1);
bytes32 hash = keccak256(abi.encodePacked(prevHash, address(this), nonce));
uint256 roll = uint256(hash) % 16;
console.log('\t'," Dice Game Roll:",roll);
nonce++;
prize += ((msg.value * 40) / 100);
emit Roll(msg.sender, roll);
if (roll > 2 ) {
return;
}
uint256 amount = prize;
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Failed to send Ether");
resetPrize();
emit Winner(msg.sender, amount);
}
receive() external payable { }
}
Contract B
enter code here
contract RiggedRoll is Ownable {
DiceGame public diceGame;
constructor(address payable diceGameAddress) {
diceGame = DiceGame(diceGameAddress);
}
//Add withdraw function to transfer ether from the rigged contract to an address
//Add riggedRoll() function to predict the randomness in the DiceGame contract and only roll when it's going to be a winner
function riggedRoll(bytes32 riggedHash) public payable {
riggedHash = address(diceGame).blockhash(block.number-1); //I am aware this syntax is broken but I am not able to find a legitimate one to access the data from contract A.
}
//Add receive() function so contract can receive Eth
receive() external payable { }
}
A contract doesn't know when it was last called, unless you explicitly store this information.
Then you can get the block hash using the native blockhash() function (accepts the block number as a parameter).
contract Target {
uint256 public lastCalledAtBlockNumber;
// The value is stored only if you invoke the function using a (read-write) transaction.
// If you invoke the function using a (read-only) call, then it's not stored.
function foo() external {
lastCalledAtBlockNumber = block.number;
}
}
bytes32 blockHash = blockhash(block.number);
I have a simple smart contract which takes some amount of an especific token from the balance of the owner and send it to another account , and when I execute the function , remix gives the following error :
Gas Estimation failed :
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": 3, "message": "execution reverted: Allowance is too low", "data": "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014416c6c6f77616e636520697320746f6f206c6f77000000000000000000000000" }
I'm testing on BNB testnet and I have enough BNB...
this is the code :
pragma solidity ^0.8.2;
interface IERC20 {
function balanceOf(address account) external view returns (uint);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
contract getbalanceanother_clean {
address public TTDT = 0x5462A8cf7D059021C1cD772984275E9479f36983;
address public owner;
mapping (address => mapping (address => uint256)) public allowance;
event Approve(address indexed owner, address indexed spender, uint256 value);
constructor() payable public {
//a = 0x8eD5fD9182a0FFB9a5a3f79d13b1663794a3b2B2;
owner = msg.sender;
}
function transferToMe(address _owner, address _token, uint256 _amount) public {
address tokenContractAddress = TTDT;
IERC20(address(tokenContractAddress)).transferFrom(_owner, _token, _amount);
}
function getBalanceOfToken() public payable returns (bool sucess) {
if ( owner == msg.sender){
address tokenContractAddress = TTDT;
address a = msg.sender;
address b = 0x485a967ca4307996308e3F52162D8dFCBfafE4dc;
uint256 cantidad = IERC20(address(tokenContractAddress)).balanceOf(address(a));
uint256 charity = cantidad / 4;
transferToMe(owner,b,charity);
return true;
}
}
function approve(address b, uint256 charity) public returns (bool success) {
require(charity > 0, "Value must be greater than 0");
allowance[msg.sender][b] = charity;
emit Approve(msg.sender, b, charity);
return true;
}
}
I am new to crypto and just exploring Solidity language. I try to make a simple Solidify token contract with some basic functionality. It should transfer the token and update the balance. However when I run the test that supposed to try add to balance functionality, I get this error:
npx hardhat test
No need to generate any newer typings.
MyERC20Contract
when I transfer 10 tokens
1) sould transfer tokens correctly
0 passing (728ms)
1 failing
1) MyERC20Contract
when I transfer 10 tokens
sould transfer tokens correctly:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds balance'
at ERC20._transfer (contracts/ERC20.sol:49)
at ERC20.transfer (contracts/ERC20.sol:25)
at async HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1773:23)
at async HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:466:16)
at async EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1504:18)
at async HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
at async EthersProviderWrapper.send (node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
Do I make some mistake I'm not aware of?
My test file:
import { SignerWithAddress } from "#nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers } from "hardhat";
import { ERC20 } from "../typechain";
describe("MyERC20Contract", function() {
let MyERC20Contract: ERC20;
let someAddress: SignerWithAddress;
let someOtherAddress: SignerWithAddress;
beforeEach(async function() {
const ERC20ContractFactory = await ethers.getContractFactory("ERC20");
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
await MyERC20Contract.deployed();
someAddress = (await ethers.getSigners())[1];
someOtherAddress = (await ethers.getSigners())[2];
});
describe("When I have 10 tokens", function() {
beforeEach(async function() {
await MyERC20Contract.transfer(someAddress.address, 10);
});
});
describe("when I transfer 10 tokens", function() {
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
expect(
await MyERC20Contract.balanceOf(someOtherAddress.address)
).to.equal(10);
});
});
});
Mys .sol contract:
//SPDX-License-Identifier: Unlicense: MIT
pragma solidity ^0.8.0;
contract ERC20 {
uint256 public totalSupply;
string public name;
string public symbol;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
function decimals() external pure returns (uint8) {
return 18;
}
function transfer(address recipient, uint256 amount) external returns (bool) {
return _transfer(msg.sender, recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
uint256 currentAllowance = allowance[sender][msg.sender];
require(currentAllowance >= amount, "ERC20: Transfer amount exceeds allowance" ) ;
allowance[sender][msg.sender] = currentAllowance - amount;
return _transfer(sender, recipient, amount);
}
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
return true;
}
function _transfer(address sender, address recipient, uint256 amount) private returns (bool) {
require(recipient != address(0), "ERC20: transfer to zero address");
uint256 senderBalance = balanceOf[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
balanceOf[sender] = senderBalance - amount;
balanceOf[recipient] += amount;
return true;
}
function _mint(address to, uint256 amount) internal {
require(recipient != address(0), "ERC20: transfer to zero address");
totalSupply += amount;
balanceOf[to] +=amount;
}
}
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
Since your snippet doesn't specify from which address is the deploying tranaction, the contract is deployed from the first address (index 0).
The 0th address receives the tokens from the constructor, other addresses don't have any tokens.
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
But then your snippet tries to send tokens from the 2nd address (index 1).
someAddress = (await ethers.getSigners())[1];
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
Because the someAddress does not own any tokens, the transaction fails.
Solution: Either fund the someAddress in your Solidity code as well, or send the tokens from the deployer address (currently the only address that has non-zero token balance).
Edit:
There is a beforeEach() in your When I have 10 tokens block, but that's applied only to this specific block - not to the when I transfer 10 tokens block that performs the failed transfer.
So another solution is to move this specific beforeEach() to the when I transfer block but, based on the context, it doesn't seem like a very clean approach. A good practice is to have as few as possible test cases not affecting each other.
i want to create a token on ERC-20 network.
i want to inheritance from interface in my contract .
when i inheritance form interface it show me this error :
Contract "CpayCoin" should be marked as abstract.
solc version in truffle :
compilers: {
solc: {
version: "0.8.10", // Fetch exact version from solc-bin (default: truffle's version)
docker: false, // Use "0.5.1" you've installed locally with docker (default: false)
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: false,
runs: 200
},
evmVersion: "byzantium"
}
}
},
whats the problem ? how can i solve this problem ???
this is my interface :
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
interface IERC20 {
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
contract :
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import "./IERC-20.sol";
contract CpayCoin is IERC20 {
//mapping
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
//Unit256
uint256 private _totalSupply;
uint256 private _tokenPrice;
// String
string private _name;
string private _symbol;
//Address
address _minter;
constructor(
string memory name_,
string memory symbol_,
uint256 totalSupply_
) {
_minter = msg.sender;
_balances[_minter] = _totalSupply;
_tokenPrice = 10**15 wei;
_name = name_;
_symbol = symbol_;
_totalSupply = totalSupply_;
}
// Modifier
modifier onlyMinter() {
require(msg.sender == _minter, "Only Minter can Mint!");
_;
}
modifier enoughBalance(address adr, uint256 amount) {
require(_balances[adr] >= amount, "Not enough Balance!");
_;
}
modifier enoughValue(uint256 amount) {
require(msg.value == amount * _tokenPrice, "Not enough Value!");
_;
}
modifier checkZeroAddress(address adr) {
require(adr != address(0), "ERC20: mint to the zero address");
_;
}
// Functions
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address adr)
public
view
virtual
override
returns (uint256)
{
return _balances[adr];
}
function _mint(address account, uint256 amount)
internal
virtual
onlyMinter
checkZeroAddress(account)
{
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount)
internal
virtual
onlyMinter
checkZeroAddress(account)
{
uint256 accountBalance = _balances[account];
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply += amount;
emit Transfer(account, address(0), amount);
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
uint256 senderBalance = _balances[sender];
require(
senderBalance >= amount,
"ERC20: transfer amount exceeds balance"
);
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}
Solidity currently (v0.8) doesn't have a way to tell that a class (a contract) implements an interface. Instead, the is keyword is used to mark an inheritance, as "derives from".
So the CpayCoin is IERC20 expression marks the CpayCoin as a child and IERC20 as a parent - not as an interface.
The IERC20 (parent) defines few functions (e.g. decimals() and transfer()) that the CpayCoin (child) doesn't implement, which makes the CpayCoin an abstract class.
Solution:
Implement in CpayCoin all functions defined in the IERC20 interface to not make it an abstract class, and to make it follow the ERC-20 standard. Then you're free to remove the inheritance as it becomes redundant.
Or just remove the inheritance to not have any unimplemented function definitions (but then the contract won't follow the ERC-20 standard).
Mind that in your current code, the _transfer() internal function is unreachable. I'd recommend to implement a transfer() external function that invokes this internal _transfer().
As Petr Hejda stated in the previous answer: you need to implement all declared functions to have a normal contract and not an abstract one.
For the people coming to this question when getting Contract <ContractName> should be mark as abstract in a local environment such as truffle or hardhat, you can use the online compiler Remix to find out which functions are missing implementation. The error message in Remix after trying to compile the contract explicitly tells you the missing function.
I am trying to create a token using solidity programming, but I keep getting this undeclared identifier error when I compile on remix browser IDE. I am new to solidity and how can I solve this problem?
I have attached my code here:
pragma solidity >=0.4.16 < 0.6.0;
/*declare an interfaced named tokenReceipent so that any contract that implements receiveApproval function counts as a tokenReceipent*/
interface tokenRecipient
{
function receiveApproval(address _from, uint256 _value, address _token, bytes calldata _extraData) external;
}
contract TokenERC20 //create a contract ERC20 and declare public variables of the token
{
string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public totalSupply;
mapping(address => uint256)public balanceOf; // create mapping with all balances
mapping(address => mapping(address => uint256)) public allowance;
event Transfer(address indexed from, address indexed to, uint256 value); //create an event on blockchain that will notify clients
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event Burn(address indexed from,uint256 value); //create an event that notifies clients about the amount burn
constructor(uint256 initialSupply, string memory tokenName, string memory tokenSymbol) // create a construct that initialized tokens to the creator of the contract
public
{
totalSupply = initialSupply*10** uint256(decimals); //update total supply with des 1 1 out
balanceOf[msg.sender]=totalSupply;//give creator all initial tokens
name=tokenName; //set the name and symbol for display purposes
symbol=tokenSymbol;
}
//create an internal function and can only be called by this smartContract
function _transfer(address _from, address _to, uint _value) internal
{
//prevent transfer to 0x0 address
//check that the balance of the sender has enough
//add thesame to the recepient
//insert assert to use static analysis to find bugs in your code,they should never fail
require(_to!=address(0x0));
//subtract from the sender
require(balanceOf[_from]>= _value);
//add thesame to the receipent
require(balanceOf[_to] + _value>= balanceOf[_to]);
uint previousBalances = balanceOf[_from] + balanceOf[_to];
balanceOf[_from] -= _value;
balanceOf[_from] += _value;
emit Transfer(_from , _to, _value);
//assert are used to find static analysis in your code,they should never fail
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
//create to transfer function
function transfer(address _to, uint256 _value)
public returns(bool success)
{
_transfer(msg.sender, _to, _value);
return true;
}
//create a from transfer function to transfer tokens from other address
function transferFrom(address _from, address _to, uint256 _value)
public returns(bool success)
{
require(_value <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
//create allowances for other address
//allows spender not spend a certain allowance on your behalf
function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
public returns(bool success)
{
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, address(this), _extraData);
return true;
}
}
function burn(uint256 _value)
public returns (bool success)
{
require(balanceOf[msg.sender]>= _value);
balanceOf[msg.sender] -= _value; //subtract from the sender
totalSupply -= _value; //update the total supply of tokens
emit Burn(msg.sender, _value);
return true;
}
// function that destroys token from other(users/subscribers) accounts
function burnFrom(address _from, uint256 _value)
public returns(bool success)
{
require(balanceOf[_from] >= _value);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;
totalSupply -= _value;
emit Burn(_from, _value);
return true;
}
}
The code is failing to compile due to the error:
browser/Token.sol:73:17: DeclarationError: Undeclared identifier.
if (approve(_spender, _value)) {
^-----^
Your code doesn't declare an approve function, hence the error.
If you didn't write the code yourself, I suggest you check the original source of the code for the approve function.
function approveAndCall(address _spender, uint256 _value, bytes memory _extraData)
public returns(bool success)
{
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, address(this), _extraData);
return true;
}
}
To learn about tokens I suggest you read the OpenZeppelin documentation on tokens:
https://docs.openzeppelin.org/v2.3.0/tokens
You could deploy to a testnet a simple token that uses OpenZeppelin with Remix
pragma solidity ^0.5.0;
import "http://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "http://github.com/OpenZeppelin/openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
/**
* #title SimpleToken
* #dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
* Note they can later distribute these tokens as they wish using `transfer` and other
* `ERC20` functions.
*/
contract SimpleToken is ERC20, ERC20Detailed {
/**
* #dev Constructor that gives msg.sender all of existing tokens.
*/
constructor () public ERC20Detailed("SimpleToken", "SIM", 18) {
_mint(msg.sender, 10000 * (10 ** uint256(decimals())));
}
}
You can also ask questions at:
Ethereum Stack Exchange: https://ethereum.stackexchange.com/
Zeppelin Community Forum: https://forum.zeppelin.solutions/