my intent is making ERC721 token can transfer by my ERC20 token only
the transfer flow is
Buyer approve ERC20 to Seller.
Seller transfer ERC721 to Buyer.
My ERC721 Token's transfer function transfer ERC20 to Seller from Buyer first, and transfer ERC721 to Buyer from Seller.
revert error occur to ERC20 transfer step.
i try to every single line delete to find revert point.
and i found that.
this is my test code
const token20 = artifacts.require("MyToken20");
const token721 = artifacts.require("MyToken721");
contract("Test", async()=>{
//...
// Buyer token20 approve to Seller
it("Token20 approve", async()=>{
var value = web3.toWei(token721Price, "ether");
await contract20.approve(seller, value, {from:buyer});
var allowed = await contract20.allowance(buyer, seller);
allowed = web3.fromWei(allowed, "ether");
assert.equal(allowed, token721Price);
});
// Seller transfer token721 to Buyer
// token20 transfer to Seller inside of function transferMy721
it("Token721 transfer", async()=>{
var allowed = await contract20.allowance(buyer, seller);
allowed = web3.fromWei(allowed, "ether");
assert.equal(allowed, token721Price);
await contract721.transferMy721(buyer, token721Id, {from:seller}); // <--- revert here
var newOwner = await contract721.ownerOf(token721Id);
assert.equal(newOwner, buyer);
});
});
and revert point in my contract is here
contract MyToken721 is ERC721Token{
string public name = "My ERC721 Token Product";
string public symbol = "MTP";
mapping(uint256 => uint256) my721TokenPrice;
MyToken20 token;
constructor(MyToken20 _token) public ERC721Token(name, symbol){
require(_token != address(0));
token = _token;
}
function mint(address _to, uint256 _tokenId, uint256 _price) public {
_mint(_to, _tokenId);
my721TokenPrice[_tokenId] = _price;
}
function transferMy721(address _to, uint256 _tokenId) public returns(bool){
require(msg.sender == ownerOf(_tokenId));
uint256 tokenPrice = my721TokenPrice[_tokenId];
if( token.transferFrom(_to, msg.sender, tokenPrice) == false ) // <--- revert here
return false;
super.approve(_to, _tokenId);
super.transferFrom(msg.sender, _to, _tokenId);
return true;
}
//...
}
and revert point in ERC20 StandardToken contract is here
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool)
{
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]); // <--- revert here
require(_to != address(0));
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
//...
}
as you can see, in my test code, i double check
allowed[_from][msg.sender]
please check my full code here
the one calling transferFrom is my erc721 contract.
so, i change test code
await contract20.approve(seller, value, {from:buyer});
change to
await contract20.approve(contract721.address, value, {from:buyer});
thank you for SylTi
Related
When creating this contract, line "_buyer.transfer(buyers[_buyer]);" generates an error " "send" and "transfer" are only available for objects of type "address payable", not "address". ".
Here is the contract code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CoinStore {
address owner;
mapping(address => uint256) buyers;
mapping(address => uint256) sellers;
uint256 coinPrice;
bool tradePaused;
constructor() {
owner = msg.sender;
}
function setCoinPrice(uint256 _price) public {
require(msg.sender == owner, "Only the owner can set the coin price.");
coinPrice = _price;
}
function registerBuyer(address _buyer, uint256 _amount) public {
require(!tradePaused, "Trading is currently paused.");
buyers[_buyer] = _amount;
}
function registerSeller(address _seller, uint256 _amount) public {
require(!tradePaused, "Trading is currently paused.");
sellers[_seller] = _amount;
}
function pauseTrade() public {
require(msg.sender == owner, "Only the owner can pause trading.");
tradePaused = true;
}
function startTrade() public {
require(msg.sender == owner, "Only the owner can start trading.");
tradePaused = false;
}
function completeSale(address _buyer, address _seller) public payable {
require(_buyer.balance >= buyers[_buyer], "Buyer does not have enough funds.");
require(_seller.balance >= sellers[_seller], "Seller does not have enough funds.");
require(msg.value == coinPrice, "Incorrect payment amount.");
_buyer.transfer(buyers[_buyer]);
_seller.transfer(sellers[_seller]);
if (msg.value > buyers[_buyer]) {
_buyer.transfer(msg.value - buyers[_buyer]);
}
}
function withdrawFunds() public {
require(msg.sender == owner, "Only the owner can withdraw funds.");
msg.sender.transfer(address(this).balance);
}
}
I am a recent learner of Solidity and am not an expert in smart contract development. Everything I could I tried. Help me please. Thank you.
The address that you are trying to send to has to be payable aswell.
Your withdraw should look like this:
function withdrawFunds() public {
require(msg.sender == owner, "Only the owner can withdraw funds.");
payable(msg.sender).transfer(address(this).balance);
}
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.
New solidity programmer here.
I'm trying to create a smart contract where a user can create a Bounty. The creator sets the bounty on the smart contract in the constructor. They can subsequently choose the recipient of the funds after evaluation of some criteria. They can cancel, increase the bounty.
I tested the code out and it appears to work, but I'm getting some warnings in remix IDE that I don't know how to fix.
Could some one show me how its supposed to be done?
contract Bounty {
address payable public owner;
address payable public provider;
uint256 private bounty;
bool isActive;
event IncreaseBounty (uint256 oldBounty, uint256 newBounty);
event Paid(address owner, address payee, uint256 amount);
event Cancel(address owner, uint256 amount);
constructor() payable {
owner = payable(msg.sender);
bounty = msg.value;
isActive = true;
}
function cancel() public {
require(isActive, "contract must be active");
require(owner == msg.sender, "Only the owner can cancel the bounty");
uint256 bountyTemp = bounty;
bounty = 0;
owner.transfer(bountyTemp);
isActive = false;
emit Cancel(msg.sender, bountyTemp);
}
function setAndTransferToProvider(address addy) public {
require(isActive, "contract must be active");
require(owner == msg.sender, "Only the owner release the funds");
provider = payable(addy);
provider.transfer(bounty);
uint256 bountyUsed = bounty;
bounty = 0;
isActive = false;
emit Paid(owner, provider, bountyUsed);
}
function increaseBounty() payable external returns (uint256) {
require(isActive, "contract must be active");
require(owner == msg.sender, "Only the owner can increase the bounty");
uint oldBounty = bounty;
bounty += uint(msg.value);
emit IncreaseBounty(oldBounty, bounty);
return bounty;
}
function getBounty() public view returns (uint256) {
require(isActive, "contract must be active");
return bounty;
}
}
Try to put this line
provider.transfer(bounty);
right before the emit of the events on every function.
You can check this article for more understanding of reentrancy attacks.
I am new to Blockchain Technology. I am following the Dapp University tutorial, when I am trying to test the sellTokens function it gives me the "Error: Returned error: VM Exception while processing transaction: revert". I think I have successfully implemented the approve function so why does it show the following error
Following are the required files you would need to review the project
Ethswap.sol
pragma solidity ^0.5.0;
import "./Token.sol";
contract Ethswap {
string public name = "Ethswap Instant Exchange";
Token public token;
uint public rate = 100;
event TokenPurchased(
address account,
address token,
uint amount,
uint rate
);
event TokenSold(
address account,
address token,
uint amount,
uint rate
);
constructor(Token _token) public {
token = _token;
}
function buytokens() public payable {
// Calculate the no of tokens to buy
uint tokenAmount = msg.value * rate;
// require Ethswap has enough balance to perform transfer of tokens
require(token.balanceOf(address(this)) >= tokenAmount);
token.transfer(msg.sender, tokenAmount);
// Emit an event
emit TokenPurchased(msg.sender, address(token), tokenAmount, rate);
}
function sellTokens(uint256 _amount) public payable {
//Calculate amoutn of ether to redeem
uint etherAmount = _amount / rate;
// require Ethswap has enough ether to perform transfer
require(address(this).balance >= etherAmount);
//Perform Sale
token.transferFrom(msg.sender, address(this), _amount);
msg.sender.transfer(etherAmount);
//Emit an event
emit TokenSold(msg.sender, address(token), _amount, rate);
}
}
Following is the smart contract code for the Dapp Token
Token.sol
pragma solidity ^0.5.0;
contract Token {
string public name = "DApp Token";
string public symbol = "DAPP";
uint256 public totalSupply = 1000000000000000000000000; // 1 million tokens
uint8 public decimals = 18;
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
constructor() public {
balanceOf[msg.sender] = totalSupply;
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= balanceOf[_from]);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
}
Following is the test javascript code for testing the smart contract
Ethswap.test.js
List item
const { assert } = require("chai")
const { default: Web3 } = require("web3")
const Token = artifacts.require("Token")
const Ethswap = artifacts.require("Ethswap")
require("chai")
.use(require("chai-as-promised"))
.should()
function tokens(n) {
return web3.utils.toWei(n, "ether")
}
contract("Ethswap", ([deployer, investor]) => {
let token
let ethSwap
before(async () => {
token = await Token.new()
ethSwap = await Ethswap.new(token.address)
await token.transfer(ethSwap.address, tokens("1000000"))
})
describe("Token Deployment", async () => {
it("contract has a name", async () => {
let token = await Token.new()
const name = await token.name()
assert.equal(name, "DApp Token")
})
})
describe("EthSwap Deployment", async () => {
it("contract has a name", async () => {
let ethSwap = await Ethswap.new(token.address)
const name = await ethSwap.name()
assert.equal(name, "Ethswap Instant Exchange")
})
it("contract has tokens", async () => {
let balance = await token.balanceOf(ethSwap.address)
assert.equal(balance.toString(), tokens("1000000"))
})
})
describe("TokenPurchased", async () => {
it("Details of the investor", async () => {
let result
before(async () => {
result = await ethSwap.buytokens({from: investor, value: web3.utils.toWei("1", "ether"),
})
//Check investor token balance after purchase
let investorBalance = await token.balanceOf(investor)
assert.equal(investorBalance.toString(), token("100"))
//Check ethswap balance after purchase
let ethSwapBalance;
ethSwapBalance = await token.balanceOf(ethSwap.address)
assert.equal(ethSwapBalance.toString(), tokens("999900"))
ethSwapBalance = await web3.eth.getBalance(ethSwap.address)
assert.equal(ethSwapBalance.toString(), web3.utils.toWei("1", "Ether"))
const event = result.logs[0].args
assert.equal(event.account, investor)
assert.equal(event.token, token.address)
assert.equal(event.amount.toString(), tokens("100").toString())
assert.equal(event.rate.toString(), "100")
})
})
})
describe("SellTokens()", async () => {
let result
before(async () => {
//Investor must approve token before purchase
await token.approve(ethSwap.address, tokens('100'))
// Investor sells token
result = await ethSwap.sellTokens(tokens('100'), { from : investor })
})
it("Allows user to instantly sell tokens", async () => {})
})
})
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/