openzeppelin-contracts | OpenZeppelin Contracts is a library for secure smart | Blockchain library
kandi X-RAY | openzeppelin-contracts Summary
Support
Quality
Security
License
Reuse
- List files recursively
openzeppelin-contracts Key Features
openzeppelin-contracts Examples and Code Snippets
Trending Discussions on openzeppelin-contracts
Trending Discussions on openzeppelin-contracts
QUESTION
The openzeppelin minimal proxy contract here has this function predictDeterministicAddress() that hashes values like the sender's address, a salt... to generate a contract address that the create2 function will also generate, when its passed the same values as dictated in this EIP.
This EIP states that an arbitrary value 0xff when hashed with a salt, senders address and the contract bytecode will always generate the same address.
Im trying to implement the predictDeterministicAddress() function on TRON blockchain but the TRON docs specify a different arbitrary value, 0x41 for implementing this same feature.
I tried to just replace the values but i can't see where the openzeppelin team used the value 0xff in their function.
Below is the openzeppelin hashing function:
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
Also due to my limited knowledge of assembly i cant fully grasp how their hashing function works exactly.
Can anyone explain to me, or help me understand how that function can be implemented on the TRON blockchain to the desired effect?
Basically i want to be able to pass the same values to create2 and also to this function on the TRON blockchain, and generate the same contract address.
ANSWER
Answered 2022-Mar-23 at 03:33According to solidity's official documentation (https://docs.soliditylang.org/en/latest/control-structures.html?highlight=create2#salted-contract-creations-create2), the algorithm for calculating create2 addresses should be as follows:
keccak256(bytes1(0xff) ++ address(factory_contract)
++ bytes32(salt) ++ keccak256(bytes(creation_code) ++ bytes(arg...)))
But on TRON, the algorithm should be as follows:
keccak256(bytes1(0x41) ++ address(factory_contract)
++ bytes32(salt) ++ keccak256(bytes(creation_code) ++ bytes(arg...)))
The difference is that the first byte given to the outer keccak256 function. EVM in ethereum is 0xff, TVM in TRON is 0x41.
Before calculating the predicted address( predicted := keccak256(add(ptr, 0x37), 0x55)
), starting from (ptr), memory data:
0x00 ~ 0x13 3d602d80600a3d3981f3363d3d373d3d3d363d73
0x14 ~ 0x27 (implementation address)
0x28 ~ 0x37 5af43d82803e903d91602b57fd5bf3 ff (This byte is the key, should be replaced by 0x41 on TRON)
0x38 ~ 0x4b (deployer address)
0x4c ~ 0x6b (salt bytes32)
0x6c ~ 0x8b (keccak256(0x00 ~ 0x37)) (This part hash is keccak256(bytes(creation_code) ++ bytes(arg...)))
This means that creation code for proxy contract will be 0x3d602d80600a3d3981f3363d3d373d3d3d363d73(impl)5af43d82803e903d91602b57fd5bf3
. We can decompile this code on (https://ethervm.io/decompile), the results are as follows:
(implementation address is replaced by 0xea674fdde714fd979de3edf0f56aa9716b898ec8)
label_0000:
// Inputs[3]
// {
// @0000 returndata.length
// @0006 returndata.length
// @0009 memory[returndata.length:returndata.length + 0x2d]
// }
0000 3D RETURNDATASIZE
0001 60 PUSH1 0x2d
0003 80 DUP1
0004 60 PUSH1 0x0a
0006 3D RETURNDATASIZE
0007 39 CODECOPY
0008 81 DUP2
0009 F3 *RETURN
// Stack delta = +1
// Outputs[3]
// {
// @0000 stack[0] = returndata.length
// @0007 memory[returndata.length:returndata.length + 0x2d] = code[0x0a:0x37]
// @0009 return memory[returndata.length:returndata.length + 0x2d];
// }
// Block terminates
000A 36 CALLDATASIZE
000B 3D RETURNDATASIZE
000C 3D RETURNDATASIZE
000D 37 CALLDATACOPY
000E 3D RETURNDATASIZE
000F 3D RETURNDATASIZE
0010 3D RETURNDATASIZE
0011 36 CALLDATASIZE
0012 3D RETURNDATASIZE
0013 73 PUSH20 0xea674fdde714fd979de3edf0f56aa9716b898ec8
0028 5A GAS
0029 F4 DELEGATECALL
002A 3D RETURNDATASIZE
002B 82 DUP3
002C 80 DUP1
002D 3E RETURNDATACOPY
002E 90 SWAP1
002F 3D RETURNDATASIZE
0030 91 SWAP2
0031 60 PUSH1 0x2b
0033 57 *JUMPI
0034 FD *REVERT
0035 5B JUMPDEST
0036 F3 *RETURN
The openzeppelin hashing function should be adjusted on TRON as follows:
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf34100000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
predicted := keccak256(add(ptr, 0x37), 0x55)
}
}
QUESTION
I have the following import statement in a Solidity contract ( this works).
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"
The interface I'm importing is at the following repo: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
My question is, what is the syntax or rules I should follow when importing from a github repo to Solidity? what does the @ sign in the import statement mean ?
ANSWER
Answered 2022-Mar-18 at 22:02Your snippet shows a direct import that searches for the file in your local directories based on the compiler config.
One of the default sources is the node_modules
directory where NPM packages are installed.
The @
symbol is just a prefix of NPM scoped packages, allowing to group more packages into the same namespace (in this case @openzeppelin/
).
To import a contract from GitHub, you can just pass its full URL:
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
Again because of the default config, the compiler downloads the remote file from GitHub to a local temp directory, and imports its contents before compiling.
QUESTION
I'm trying to use my custom ERC20 contract that is stored in my local storage in the SWAP project that I'm working on.
the error I'm getting while trying to use the erc20 import inside the SWAP contract:
unresolved import `erc20::Erc20`
no `Erc20` in the root
help: a similar name exists in the module: `erc20`rustc(E0432)
swap.rs(10, 9): no `Erc20` in the root
Here is how I import the erc20 module in SWAP.rs:
#![cfg_attr(not(feature = "std"), no_std)]
use ink_lang as ink;
#[ink::contract]
mod swapv1 {
#[cfg(not(feature = "ink-as-dependency"))]
use erc20::Erc20; <-----
use ink_env::call::FromAccountId;
use ink_prelude::string::String;
// snip....
This is how I import the ERC20 module inside SWAP.rs .toml file:
erc20 = { path = "../erc20/", version="3.0.0-rc4", default-features = false, features = ["ink-as-dependency"] }
I've also added the following configuration to the ERC20 .toml file:
crate-type = [
"rlib",
]
Here is the content of the ERC20 module file:
#![cfg_attr(not(feature = "std"), no_std)]
pub use self::erc20::Erc20;
use ink_lang as ink;
#[ink::contract]
pub mod erc20 {
#[cfg(not(feature = "ink-as-dependency"))]
use ink_prelude::string::String;
use ink_storage::traits::SpreadAllocate;
#[ink(storage)]
#[derive(SpreadAllocate)]
pub struct Erc20 {
/// Total token supply.
total_supply: Balance,
/// Mapping from owner to number of owned token.
balances: ink_storage::Mapping,
/// Mapping of the token amount which an account is allowed to withdraw
/// from another account.
allowances: ink_storage::Mapping<(AccountId, AccountId), Balance>,
/// Token name
name: String,
/// Token symbol (ticker)
symbol:String,
}
/// Event emitted when a token transfer occurs.
#[ink(event)]
pub struct Transfer {
#[ink(topic)]
from: Option,
#[ink(topic)]
to: Option,
value: Balance,
}
/// Event emitted when an approval occurs that `spender` is allowed to withdraw
/// up to the amount of `value` tokens from `owner`.
#[ink(event)]
pub struct Approval {
#[ink(topic)]
owner: AccountId,
#[ink(topic)]
spender: AccountId,
value: Balance,
}
/// The ERC-20 error types.
#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum Error {
/// Returned if not enough balance to fulfill a request is available.
InsufficientBalance,
/// Returned if not enough allowance to fulfill a request is available.
InsufficientAllowance,
}
/// The ERC-20 result type.
pub type Result = core::result::Result;
impl Erc20 {
/// Creates a new ERC-20 contract with the specified initial supply.
#[ink(constructor)]
pub fn new(name: String, symbol: String, initial_supply: Balance) -> Self {
let caller = Self::env().caller();
let me = ink_lang::utils::initialize_contract(|contract: &mut Self| {
contract.balances.insert(caller, &initial_supply);
contract.allowances.insert((caller,caller),&initial_supply);
contract.symbol = symbol;
contract.name = name;
});
Self::env().emit_event(Transfer {
from: None,
to: Some(caller),
value: initial_supply,
});
me
}
/// Returns the total token supply.
#[ink(message)]
pub fn total_supply(&self) -> Balance {
self.total_supply
}
/// Returns the account balance for the specified `owner`.
///
/// Returns `0` if the account is non-existent.
#[ink(message)]
pub fn balance_of(&self, owner: AccountId) -> Balance {
self.balances.get(&owner).unwrap_or(0)
}
/// Returns the amount which `spender` is still allowed to withdraw from `owner`.
///
/// Returns `0` if no allowance has been set `0`.
#[ink(message)]
pub fn allowance(&self, owner: AccountId, spender: AccountId) -> Balance {
self.allowances.get(&(owner, spender)).unwrap_or(0)
}
/// Transfers `value` amount of tokens from the caller's account to account `to`.
///
/// On success, a `Transfer` event is emitted.
///
/// # Errors
///
/// Returns `InsufficientBalance` error if there are not enough tokens on
/// the caller's account balance.
#[ink(message)]
pub fn transfer(&mut self, to: AccountId, value: Balance) -> Result<()> {
let from = self.env().caller();
self.transfer_from_to(from, to, value)
}
/// Allows `spender` to withdraw from the caller's account multiple times, up to
/// the `value` amount.
///
/// If this function is called again it overwrites the current allowance with `value`.
///
/// An `Approval` event is emitted.
#[ink(message)]
pub fn approve(&mut self, spender: AccountId, value: Balance) -> Result<()> {
let owner = self.env().caller();
self.allowances.insert((owner, spender), &value);
self.env().emit_event(Approval {
owner,
spender,
value,
});
Ok(())
}
/// Transfers `value` tokens on the behalf of `from` to the account `to`.
///
/// This can be used to allow a contract to transfer tokens on one's behalf and/or
/// to charge fees in sub-currencies, for example.
///
/// On success, a `Transfer` event is emitted.
///
/// # Errors
///
/// Returns `InsufficientAllowance` error if there are not enough tokens allowed
/// for the caller to withdraw from `from`.
///
/// Returns `InsufficientBalance` error if there are not enough tokens on
/// the the account balance of `from`.
#[ink(message)]
pub fn transfer_from(
&mut self,
from: AccountId,
to: AccountId,
value: Balance,
) -> Result<()> {
let caller = self.env().caller();
let allowance = self.allowance(from, caller);
if allowance < value {
return Err(Error::InsufficientAllowance)
}
self.transfer_from_to(from, to, value)?;
self.allowances.insert((from, caller), &(allowance - value));
Ok(())
}
/// Transfers `value` amount of tokens from the caller's account to account `to`.
///
/// On success, a `Transfer` event is emitted.
///
/// # Errors
///
/// Returns `InsufficientBalance` error if there are not enough tokens on
/// the caller's account balance.
fn transfer_from_to(
&mut self,
from: AccountId,
to: AccountId,
value: Balance,
) -> Result<()> {
let from_balance = self.balance_of(from);
if from_balance < value {
return Err(Error::InsufficientBalance)
}
self.balances.insert(from, &(from_balance - value));
let to_balance = self.balance_of(to);
self.balances.insert(to, &(to_balance + value));
self.env().emit_event(Transfer {
from: Some(from),
to: Some(to),
value,
});
Ok(())
}
}
/// The IERC20Metadata (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/IERC20Metadata.sol)
impl Erc20 {
/// Returns the token name.
#[ink(message)]
pub fn name(&self) -> String {
self.name.clone()
}
/// Returns the token name.
#[ink(message)]
pub fn symbol(&self) -> String {
self.symbol.clone()
}
/// Returns the decimal places of the token.
#[ink(message)]
pub fn decimals(&self) -> u8 {
18
}
}
}
ANSWER
Answered 2022-Mar-04 at 15:42Change
use erc20::Erc20;
to
use erc20::Erc20Ref;
Put this at the top of the ERC20 contract:
pub use self::erc20::{Erc20, Erc20Ref};
You can see an example of this in the subber contract where it specifies itself as SubberRef
and is then called from the main delegator contract
QUESTION
*****top lines of my .sol file // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract ParcelAsset is ERC721 {
******command line VScode brownie compile contracts\ParcelAsset.sol
I get this error. ValueError: Invalid NPM block in '>=0.6.0 <0.8.0 import "@openzeppelin/contracts/token/ERC721/ERC721.sol"': 'import'
*********** snippet of my brownie-config.yaml dependencies:
- smartcontractkit/chainlink-brownie-contracts@1.1.1
- OpenZeppelin/openzeppelin-contracts@3.4.0 compiler: solc: remappings:
- '@chainlink=smartcontractkit/chainlink-brownie-contracts@1.1.1'
- '@openzeppelin=OpenZeppelin/openzeppelin-contracts@3.4.0'
I have tried npm install @openzeppelin/contracts and upadating solidity to 0.8.0
Anyone known what I am doing wrong?
ANSWER
Answered 2022-Feb-10 at 20:08I solved it by doing: npm install @chainlink/contracts --save
I personally didn't bother importing openzeppelin because all safemath functionalities (if that is what you are importing) are already implemented into solidity 0.8.0, so if you're using solidity 0.8.0, the safemath library is obsolete
QUESTION
I tried all that you mentioned in the discussion here (in other questions) and at https://github.com/smartcontractkit/full-blockchain-solidity-course-py/discussions/522 , however it is not solving the issue for me, I also noticed that the current compiler version remains (current compiler is 0.6.12+commit.27d51765.Windows.msvc). But when I right click and select Solidty:Compiler information, it shows 0.8.0.
from output:
Retrieving compiler information:
Compiler using remote version: 'v0.8.0+commit.c7dfd78e', solidity version: 0.8.0+commit.c7dfd78e.Emscripten.clang
Not sure if that is related to the issue I face. Anyways starting with the problem I see when running brownie compile. I get the error below:
error in terminal:
PS D:\Python projects\Solidity dev\demo\smartcontract-lottery> brownie compile
INFO: Could not find files for the given pattern(s).
Brownie v1.17.2 - Python development framework for Ethereum
Compiling contracts...
Solc version: 0.6.12
Optimizer: Enabled Runs: 200
EVM Version: Istanbul
CompilerError: solc returned the following errors:
C:/Users/rosne/.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.3.0/contracts/access/Ownable.sol:3:1: ParserError: Source file requires different compiler version (current compiler is 0.6.12+commit.27d51765.Windows.msvc) - note that nightly builds are considered to be strictly less than the released version
pragma solidity ^0.8.0;
^---------------------^
C:/Users/rosne/.brownie/packages/smartcontractkit/chainlink-brownie-contracts@0.2.1/contracts/src/v0.8/VRFConsumerBase.sol:2:1: ParserError: Source file requires different compiler version (current compiler is 0.6.12+commit.27d51765.Windows.msvc) - note that nightly builds are considered to be strictly less than the released version
pragma solidity ^0.8.0;
^---------------------^
PS D:\Python projects\Solidity dev\demo\smartcontract-lottery>
My .sol file is Lottery.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract Lottery is VRFConsumerBase, Ownable {
uint256 usdEntryFee;
address payable[] public players;
address payable public recentWinner;
uint256 public randomness;
AggregatorV3Interface internal ethUsdPriceFeed;
enum LOTTERY_STATE {
OPEN,
CLOSED,
CALCULATING_WINNER
}
LOTTERY_STATE public lottery_state;
uint256 public fee;
bytes32 public keyhash;
constructor(
address _priceFeedAddress,
address _vrfCoordinator,
address _link,
uint256 _fee,
bytes32 _keyhash
) public VRFConsumerBase(_vrfCoordinator, _link) {
usdEntryFee = 50 * (10**18);
ethUsdPriceFeed = AggregatorV3Interface(_priceFeedAddress);
lottery_state = LOTTERY_STATE.CLOSED;
fee = _fee;
keyhash = _keyhash;
}
function enter() public payable {
//$50 min
require(lottery_state == LOTTERY_STATE.OPEN);
require(msg.value >= getEntranceFee(), "Not enough ETH!");
players.push(payable(msg.sender));
}
function getEntranceFee() public view returns (uint256) {
(, int256 price, , , ) = ethUsdPriceFeed.latestRoundData();
uint256 adjustedPrice = uint256(price) * 10**12; //18 decimals
//$50, 2000 ETH
//50/2000
//50*10000/2000
uint256 costToEnter = (usdEntryFee * 10**18) / adjustedPrice;
return costToEnter;
}
function startLottery() public onlyOwner {
require(
lottery_state == LOTTERY_STATE.CLOSED,
"cant start a new lottery yet"
);
lottery_state = LOTTERY_STATE.OPEN;
}
function endLottery() public onlyOwner {
lottery_state = LOTTERY_STATE.CALCULATING_WINNER;
bytes32 requestId = requestRandomness(keyhash, fee);
}
function FulfillRandomness(bytes32 _requestId, uint256 _randomness)
internal
override
{
require(
lottery_state == LOTTERY_STATE.CALCULATING_WINNER,
"you arent there yet!"
);
require(_randomness > 0, "random not found");
uint256 indexOfWinner = _randomness % players.length;
recentWinner = players[indexOfWinner];
recentWinner.transfer(address(this).balance);
//reset
players = new address payable[](0);
lottery_state = LOTTERY_STATE.CLOSED;
randomness = _randomness;
}
}
I also tried to google some solutions so my settings.json file is a bit different but that didnt help too.
settings.json:
{
"solidity.compileUsingRemoteVersion": "v0.8.0+commit.c7dfd78e",
"solidity.defaultCompiler": "remote",
"solidity.compileUsingLocalVersion": "d:\\Python projects\\Solidity dev\\demo\\smartcontract-lottery\\soljson-v0.8.0+commit.c7dfd78e.js"
// "solidity.compileUsingRemoteVersion": "v0.7.4+commit.3f05b770",
// "solidity.enableLocalNodeCompiler": false
}
In the brownie-config.yaml, I tried all the versions of openzepplin contracts too from old to latest (4.4.0, 4.3.0,4.3.2 etc), but same error.
brownie-config.yaml
dependencies:
- smartcontractkit/chainlink-brownie-contracts@1.1.1
- OpenZeppelin/openzeppelin-contracts@4.3.0
compiler:
solc:
remappings:
- '@chainlink=smartcontractkit/chainlink-brownie-contracts@0.2.1'
- '@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.3.0'
networks:
mainnet-fork:
eth_usd_price_feed: '0xaEA2808407B7319A31A383B6F8B60f04BCa23cE2'
I also tried to change the compiler in lottery.sol file with
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
Now I get a different error. Completely lost here :(
terminal:
INFO: Could not find files for the given pattern(s).
Brownie v1.17.2 - Python development framework for Ethereum
Compiling contracts...
Solc version: 0.8.11
Optimizer: Enabled Runs: 200
EVM Version: Istanbul
CompilerError: solc returned the following errors:
ParserError: Source file requires different compiler version (current compiler is 0.8.11+commit.d7f03943.Windows.msvc) - note that nightly builds are considered to be strictly less than the released version
--> C:/Users/rosne/.brownie/packages/smartcontractkit/chainlink-brownie-contracts@0.2.1/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol:2:1:
|
2 | pragma solidity ^0.6.0;
| ^^^^^^^^^^^^^^^^^^^^^^^
PS D:\Python projects\Solidity dev\demo\smartcontract-lottery>
I am very new to programing in solidity and this is the first course I am following, I don't want to give up so easily, any help is much appreciated.
ANSWER
Answered 2022-Jan-02 at 03:09i had the same issue. i had this compiler setting:
pragma solidity >=0.4.22 <0.9.0;
Since we are importing from openzeppelin
, I visied github repo and saw that it uses pragma solidity ^0.8.0;
So changed my setting to
pragma solidity >=0.4.22 <0.8.0;
After compilation I searched for ">=0.6.0 <0.8.0" and got those files. They all from openzeppelin
I did not add solc version to the brownie-yaml file
QUESTION
What I am trying to achieve is calling a transferFrom
from ERC20 contract inside an ERC721 contract like this:
My ERC20 contract:
pragma solidity ^0.7.0;
import "../openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "../openzeppelin-contracts/contracts/math/SafeMath.sol";
contract ERC20Token is IERC20 {
using SafeMath for uint256;
bytes32[] public candidateList;
uint public totalTokens;
uint public balanceTokens;
uint public tokenPrice;
// what is the voter address?
// total tokens purchased
// tokens voted per candidate
struct voter {
address voterAddress;
uint tokensBought;
uint256[] tokensUsedPerCandidate;
}
mapping(address => voter) public voterInfo;
mapping(bytes32 => uint256) public votesReceived;
string public symbol;
string public name;
uint8 public decimals;
mapping(address => uint256) balances;
mapping(address => mapping(address => uint256)) allowed;
constructor(uint256 _totalTokens, uint256 _tokenPrice, bytes32[] memory _candidateNames) {
symbol = "NCToken";
name = "NCSOFT TOKEN";
decimals = 0;
totalTokens = _totalTokens;
balanceTokens = _totalTokens;
tokenPrice = _tokenPrice;
candidateList = _candidateNames;
emit Transfer(address(0), msg.sender, totalTokens);
function transferFrom(address from, address to, uint256 tokens) public override returns (bool) { //This is the function I am trying to call from ERC721 contract
balances[from] = SafeMath.sub(balances[from], tokens);
allowed[from][msg.sender] = SafeMath.sub(allowed[from][msg.sender], tokens);
balances[to] = SafeMath.add(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
}
My ERC721 contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
import "../openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";
import "../openzeppelin-contracts/contracts/math/SafeMath.sol";
import "../openzeppelin-contracts/contracts/utils/Address.sol";
import "../openzeppelin-contracts/contracts/utils/Counters.sol";
import "./ERC20Token.sol";
contract NFTtoken is ERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
bytes32[] candidates = [bytes32('Rama'), bytes32('Nick'), bytes32('Jose')];
ERC20Token ERC20TokenContract = new ERC20Token(1000, 1, candidates); //instantiating an ERC20 contract
address payable public owner;
mapping(bytes4 => bool) supportedInterfaces;
mapping(uint256 => address) tokenOwners; //a mapping from NFT ID to the address that owns it
mapping(address => uint256) balances; //a mapping from NFT ID to the address that owns it
mapping(uint256 => address) allowance; //a mapping from NFT ID to approved address
mapping(address => mapping(address => bool)) operators; //Mapping from owner address to mapping of operator addresses.
// mapping (uint256 => string) idToUri;
uint8 public decimals;
uint256[] public allValidTokenIds;
mapping(uint256 => uint256) private allValidTokenIndex;
string[] public allNFTNames;
struct NFT {
//uint NFTID;
string name;
address creator;
}
mapping(address => NFT) public nftInfo;
constructor() ERC721("NC NFT example", "NCNFT") {
owner = msg.sender;
decimals = 0;
}
function mint(string calldata nftName) external payable {
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
nftInfo[msg.sender].name = nftName;
nftInfo[msg.sender].creator = msg.sender;
allValidTokenIndex[newItemId] = allValidTokenIds.length;
allValidTokenIds.push(newItemId);
_tokenIds.increment();
}
function transferNFT(address from, address to, uint256 tokenId) public returns (bool){
transferFrom(from, to, tokenId);
ERC20TokenContract.transferFrom(to, nftInfo[from].creator, 10);
//<-----***********This is throwing an error! I am trying to call ERC20Token.transferFrom.
}
function allNFTs() public view returns (uint256[] memory) {
return allValidTokenIds;
}
}
Error Message when transferNFT
from ERC721 is called.
MetaMask - RPC Error: [ethjs-query] while formatting outputs from RPC '{"value":{"code":-32603,"data":{"message":"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token","code":-32000,"data":{"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f":{"error":"revert","program_counter":7889,"return":"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000","reason":"ERC721: operator query for nonexistent token"},"stack":"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\n at Function.RuntimeError.fromResults (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n at BlockchainDouble.processBlock (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:24)\n at runMicrotasks ()\n at processTicksAndRejections (internal/process/task_queues.js:93:5)","name":"RuntimeError"}}}}'
{code: -32603, message: `[ethjs-query] while formatting outputs from RPC '{…/task_queues.js:93:5)","name":"RuntimeError"}}}}'`}
code: -32603
message: "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\",\"code\":-32000,\"data\":{\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\":{\"error\":\"revert\",\"program_counter\":7889,\"return\":\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\",\"reason\":\"ERC721: operator query for nonexistent token\"},\"stack\":\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\n at Function.RuntimeError.fromResults (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\runtimeerror.js:94:13)\\n at BlockchainDouble.processBlock (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\blockchain_double.js:627:24)\\n at runMicrotasks ()\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\",\"name\":\"RuntimeError\"}}}}'"
[[Prototype]]: Object
localhost/:1 Uncaught (in promise)
{code: -32603, message: `[ethjs-query] while formatting outputs from RPC '{…/task_queues.js:93:5)","name":"RuntimeError"}}}}'`, stack: '{\n "code": -32603,\n "message": "[ethjs-query] wh…gaeaoehlefnkodbefgpgknn/background-0.js:1:216902)'}
code: -32603
message: "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\",\"code\":-32000,\"data\":{\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\":{\"error\":\"revert\",\"program_counter\":7889,\"return\":\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\",\"reason\":\"ERC721: operator query for nonexistent token\"},\"stack\":\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\n at Function.RuntimeError.fromResults (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\runtimeerror.js:94:13)\\n at BlockchainDouble.processBlock (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\blockchain_double.js:627:24)\\n at runMicrotasks ()\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\",\"name\":\"RuntimeError\"}}}}'"
stack: "{\n \"code\": -32603,\n \"message\": \"[ethjs-query] while formatting outputs from RPC '{\\\"value\\\":{\\\"code\\\":-32603,\\\"data\\\":{\\\"message\\\":\\\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\",\\\"code\\\":-32000,\\\"data\\\":{\\\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\\\":{\\\"error\\\":\\\"revert\\\",\\\"program_counter\\\":7889,\\\"return\\\":\\\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\\\",\\\"reason\\\":\\\"ERC721: operator query for nonexistent token\\\"},\\\"stack\\\":\\\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\\n at Function.RuntimeError.fromResults (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\utils\\\\\\\\runtimeerror.js:94:13)\\\\n at BlockchainDouble.processBlock (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\blockchain_double.js:627:24)\\\\n at runMicrotasks ()\\\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\\\",\\\"name\\\":\\\"RuntimeError\\\"}}}}'\",\n \"stack\": \"Error: [ethjs-query] while formatting outputs from RPC '{\\\"value\\\":{\\\"code\\\":-32603,\\\"data\\\":{\\\"message\\\":\\\"VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\",\\\"code\\\":-32000,\\\"data\\\":{\\\"0x0b5d04087c39a8caa2f730815e42f619d33c9d0c3b8682c8c01d3f1ecf0e7d0f\\\":{\\\"error\\\":\\\"revert\\\",\\\"program_counter\\\":7889,\\\"return\\\":\\\"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4552433732313a206f70657261746f7220717565727920666f72206e6f6e6578697374656e7420746f6b656e0000000000000000000000000000000000000000\\\",\\\"reason\\\":\\\"ERC721: operator query for nonexistent token\\\"},\\\"stack\\\":\\\"RuntimeError: VM Exception while processing transaction: revert ERC721: operator query for nonexistent token\\\\n at Function.RuntimeError.fromResults (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\utils\\\\\\\\runtimeerror.js:94:13)\\\\n at BlockchainDouble.processBlock (C:\\\\\\\\Program Files\\\\\\\\WindowsApps\\\\\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\\\\\app\\\\\\\\resources\\\\\\\\static\\\\\\\\node\\\\\\\\node_modules\\\\\\\\ganache-core\\\\\\\\lib\\\\\\\\blockchain_double.js:627:24)\\\\n at runMicrotasks ()\\\\n at processTicksAndRejections (internal/process/task_queues.js:93:5)\\\",\\\"name\\\":\\\"RuntimeError\\\"}}}}'\\n at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:148782)\\n at s (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146325)\\n at Object.internal (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146935)\\n at y. (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:210928)\\n at Object.h (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:35204)\\n at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:117610)\\n at y.a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:118146)\\n at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:46740)\\n at y.setTxStatusFailed (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:45972)\\n at B._failTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:225990)\\n at B.approveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:217659)\\n at async B.updateAndApproveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:216902)\"\n}\n at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:148782)\n at s (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146325)\n at Object.internal (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:146935)\n at y. (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:210928)\n at Object.h (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:18:35204)\n at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:117610)\n at y.a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-0.js:1:118146)\n at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:46740)\n at y.setTxStatusFailed (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-1.js:1:45972)\n at B._failTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:225990)\n at B.approveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:217659)\n at async B.updateAndApproveTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-0.js:1:216902)"
[[Prototype]]: Object
setTimeout (async)
(anonymous) @ inpage.js:1
write @ inpage.js:1
This is my javascript file calling the functions from both contracts.
// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import voting_artifacts from '../../build/contracts/Voting.json'
import voting_artifacts2 from '../../build/contracts/DeedToken.json'
window.App = {
start: function() {
var self = this;
self.transferNFT();
},
transferNFT: function() {
NFTContract.deployed().then(function(contractInstance) {
let toAddress = $("#to-address").val();
let NFTid_temp = $("#nft-id").val();
let NFTid = NFTid_temp.substring(7);
contractInstance.transferFrom(web3.currentProvider.selectedAddress, toAddress, NFTid, {gas: 140000, from: web3.eth.accounts[0]});
})
}
}
window.addEventListener('load', async function() {
if (window.ethereum) {
await window.ethereum.send('eth_requestAccounts');
window.web3 = new Web3(window.ethereum);
}
else {
console.warn("No web3 detected.");
window.web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"));
}
App.start();
});
ANSWER
Answered 2022-Jan-11 at 14:03In order to interact with an ERC20 token, you have to create an instance of it from the desired contract. You would need to import ERC20 to your nfts contracts, and then create an ERC20 token instance pointing to your token. It would be something like this:
// Inside the nfts contract
ERC20 token = ERC20("your token address here");
And then you will be able to interact with that token as:
token.transferFrom("args");
Hope you find this information useful :)
QUESTION
I am very new to Solidity, and have recently been working on trying to learn the ropes. For reference, I have been using code from this video (https://www.youtube.com/watch?v=tBMk1iZa85Y) as a primer after having gone through the basic crypto zombies tutorial series.
I have been attempting to adapt the Solidity contract code presented in this video (which I had functioning just fine!) to require a Burn of a specified amount of an ERC-20 token before minting an NFT as an exercise for myself. I thought I had what should be a valid implementation which compiled in Remix, and then deployed to Rinkeby. I call the allowAccess function in Remix after deploying to Rinkeby, and that succeeds. But, when I call the mint function with the two parameters, I get: "gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? execution reverted."
If I still send the transaction, metamask yields "Transaction xx failed! Transaction encountered an error.".
I'm positive it has to do with "require(paymentToken.transfer(burnwallet, amounttopay),"transfer Failed");", though I'm not sure what's wrong. Below is my entire contract code. I'm currently just interacting with the Chainlink contract on Rinkeby as my example, since they have a convenient token faucet.
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol";
contract myNFTwithBurn is ERC721, Ownable {
address externalTokenAddress = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709; //Token Type to burn on minting
uint256 amounttopay = 5; //number of these tokens to burn
IERC20 paymentToken = IERC20(externalTokenAddress); //my code: create an interface of the external token
address burnwallet = 0x000000000000000000000000000000000000dEaD; //burn wallet
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
using Strings for uint256;
// Optional mapping for token URIs
mapping (uint256 => string) private _tokenURIs;
// Base URI
string private _baseURIextended;
constructor() ERC721("NFTsWithBurn","NWB") {
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = _baseURI();
// If there is no base URI, return the token URI.
if (bytes(base).length == 0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
return string(abi.encodePacked(base, tokenId.toString()));
}
function allowAccess() public
{
paymentToken.approve(address(this), 5000000); //This is my attempt to allow the contract access to the user's external tokens, in this case Chainlink (paymentToken)
}
function mintItem(address to, string memory tokenURI)
public
onlyOwner
returns (uint256)
{
require(paymentToken.transfer(burnwallet, amounttopay),"transfer Failed"); //Try to transfer 5 chainlink to the burn wallet
_tokenIds.increment();
uint256 id = _tokenIds.current();
_mint(to, id);
_setTokenURI(id, tokenURI);
return id;
}
}
If anybody can at least point me to what I'm doing completely wrong in the code that I've added, please do! TIA!
ANSWER
Answered 2022-Jan-14 at 18:56I'm not sure why are you trying to burn link in order to mint and nft but first check if the link code does not have a require that check if the destination address is the burn address if it has then burn the link is not possible and you should use any other erc20 maybe your own erc20, also your contract probably does not have any link and if you want to transfer the link from the user you should do this in the contract paymentToken.transferFrom(msg.sender,destinationAddress,amount)
and if the user previously approve your contract you will able to send the tokens, and i suppose that the purpose of the allowAccess function is to make the user approve the contract to move the tokens that will never work, the approve function let's anyone that call it approve any address to move an amount of tokens, the thing is that to know who is approving to let other to move the tokens the function use msg.sender to explain how this work take a look at this example
let's say that your contract is the contract A and the link contract is the contract B
now a user call allowAccess in the contract A, so here the msg.sender is the user because they call the function
now internally this function call approve on contract B, here the contract A is the msg.sender, because the contract is who call the function
so what allowAccess is really doing is making the contract approving itself to move their own tokens that I assume it doesn't have
QUESTION
I'm pretty new to programing in solidity and I'm currently trying to run a simple smart contract in Remix, seen bellow:
pragma solidity ^0.8.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
contract Swap {
address public owner;
uint256 public balance;
event TransferReceived(address _from, uint _amount);
event TransferSent(address _from, address _destAddr, uint _amount);
constructor() {
owner = msg.sender;
}
receive() payable external {
balance += msg.value;
emit TransferReceived(msg.sender, msg.value);
}
function withdraw(uint amount, address payable destAddr) public {
require(msg.sender == owner, "Only owner can withdraw funds");
require(amount <= balance, "Insufficient funds");
destAddr.transfer(amount);
balance -= amount;
emit TransferSent(msg.sender, destAddr, amount);
}
function transferERC20(IERC20 token, address to, uint256 amount) public {
require(msg.sender == owner, "Only owner can withdraw funds");
uint256 erc20balance = token.balanceOf(address(this));
require(amount <= erc20balance, "balance is low");
token.transfer(to, amount);
emit TransferSent(msg.sender, to, amount);
}
}
While I can successfully send BNB and call the withdraw
function giving the value sent and my wallet address in the BSC testnet, I'm having issues when running the transferERC20
function. The only output that I get when calling this method is the following message:
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": -32000, "message": "execution reverted" }
I've tried several different addresses that I found in the testnet.bscscan website for BNB while making sure that the contract had enough funds for transfering, but I had no success.
Can someone suggest what might be going wrong in my contract/setup? Am I making this transfer properly?
ANSWER
Answered 2022-Jan-04 at 20:41fix constrcutor
constructor() {
// payable allows payment of ether with a call.
owner = payable(msg.sender);
}
make sure those require
statements are satisfied
require(msg.sender == owner, "Only owner can withdraw funds");
require(amount <= balance, "Insufficient funds");
check that you are connected to correct network
QUESTION
I have taken different courses and even tho they explain how to make a token I haven't been able to learn how to implement tokenomics.
For example fees for transactions, burning to LP etc...
I leave a link to the openzeppelin standard
Would be great to have some more detailed examples on it.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol
ANSWER
Answered 2021-Dec-11 at 22:16What you are looking for is to make a custom _transfer()
method by overriding the one provided in the OpenZeppelin ERC20 standard.
You can check with the "OXB" (oxbull.tech
) token, which implements this type of fee, but basically you just take tokens from the sender before sending them to the receiver, and once you are done charging the fees you can send the remaining tokens to the receiver.
An example would be:
function _transfer(address sender, address recipient, uint256 amount) private {
require(sender != address(0), "BEP20: transfer from the zero address");
require(balanceOf(sender) >= amount, "BEP2': not enough balance");
uint256 tokensToBurn = amount.mul(burningFee).div(100);
amount = amount.sub(tokensToBurn);
balances[sender] = balances[sender].sub(amount);
_burn(sender, tokensToBurn);
balances[recipient] = balances[recipient].add(amount);
}
Options of what you can do are infinite. Hope this is helpful.
QUESTION
I have two contract that are separately deployed.
FirstContract.sol
contract FirstContract is ERC721 {
using Counters for Counters.Counter;
Counters.Counter public _id;
address payable _admin;
constructor(address admin) ERC721("Token Name", "TOKEN") {
_admin = payable(admin);
}
function incrementToken() public {
_id.increment();
}
}
SecondContract.sol
import "./FirstContract.sol";
contract SecondContract {
FirstContract firstContract;
constructor(address _address) {
firstContract = FirstContract(_address);
}
function increment() external {
firstContract.incrementToken();
}
function transferValue(uint value) external {
firstContract._admin.transfer(value); // error here
}
}
I'm getting the error:
Member "transfer" not found or not visible after argument-dependent lookup in function () view external returns (address payable).
I'm not sure why this error occurs because the function is marked public
here.
ANSWER
Answered 2021-Nov-18 at 15:46FirstContract
derives from ERC721
but your link at the end of the question points at ERC20
contract. So the definition of transfer()
in the ERC20
is not relevant in this context.
firstContract._admin.transfer(value);
This snippet is attempting to use the Solidity native transfer()
member of the address payable
type, i.e. transfer ETH (not an ERC20 token). But it's failing because the firstContract._admin
is not visible.
It would be visible if the FirstContract
was a parent of SecondContract
, as well as if the _admin
had public
visibility modifier. Since it doesn't have any visibility modifier specified, the default value internal
is used.
- Give the
_admin
property thepublic
visibility modifier
address payable public _admin;
Then you need to change the call of firstContract._admin
(property) to firstContract._admin()
(function) because of the way that the compiler handles public properties in external contracts. See more about autogenerated getter functions in the docs.
- Change the call from the property to the function
firstContract._admin().transfer(value);
Mind that the SecondContract
doesn't hold any ETH and currently has no way to receive any. So if you were trying to transfer()
more than the current balance of the SecondContract
(which is 0), the transaction would revert.
For testing purposes, you can add the payable
modifier to the constructor and send it some ETH with the deployment transaction, so that you can test the transferValue()
.
constructor(address _address) payable {
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install openzeppelin-contracts
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page