BEP-20/ERC20 - how to add Tax fees when token is transfer? - solidity

Full Source:https://github.com/laronlineworld/NewToken/blob/main/NewToken.sol
This token only deduct tax when selling on dex and tax goes to specific address and the transfer doesn't take any fee.
How to add fee when token was transfer? And fees will go to specific address.
Summary: Tokenomics will be BUY:0% SELL:5% TRANSFER OF TOKEN:5%. Is this possible?
/**
* #dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `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.sub(amount);
}
bool takeFee = true;
if (_isExcludedFromFee[sender]) {
takeFee = false;
}
if(recipient==pairAddress&&takeFee){
uint256 taxFee = amount.mul(dexTaxFee).div(10000);
_balances[taxAddress] = _balances[taxAddress].add(taxFee);
emit Transfer(sender, taxAddress, taxFee);
amount = amount.sub(taxFee);
}
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}

this question has already been answered here: Is it possible to reserve an address on Solidity smart contract creation for taxes collection?
To resume, you need to change the logic of the transfer() function. But be careful as it will break on most dex because it's not an ERC20 token anymore.

Related

Solidity, contract hidden mint

Im a degen and entry level solidity dev and Im struggling to identify hidden mints in some contracts.
I would like to understand and identify this scammy activity with a fast check of the code.
Is there a generic functions or code structure to pay attention to?
Also, this are some function I noticed are suspicious. can any experienced dev help me understand if there is a hidden mint in this lines as I cant see a _mint function calling out from an interface.
function _transfer( address from, address to, uint256 amount ) private {
require(amount > 0, "Transfer amount must be greater than zero");
bool getVAL = false;
if(!allowed[from] && !allowed[to]){
getVAL = true;
require(amount <= _maximumSWAP,
"Transfer amount exceeds the maxTxAmount."); }
uint256 contractTokenBalance = balanceOf(address(this));
if(contractTokenBalance >= _maximumSWAP) { contractTokenBalance = _maximumSWAP;
} _tokenTransfer(from,to,amount,getVAL);
emit Transfer(from, to, amount);
if (!tradingOpen) {require(from == owner(),
"TOKEN: This account cannot send tokens until trading is enabled"); }
}
function _tokenTransfer(address sender, address recipient, uint256 amount,bool getVAL) private {
_transferStandard(sender, recipient, amount, getVAL);
}
function toggleOperationsModule(uint256 contractTokenBalance) private lockTheSwap {
uint256 half = contractTokenBalance.div(2);
uint256 otherHalf = contractTokenBalance.sub(half);
uint256 initialBalance = address(this).balance;
swapTokensForEth(half);
uint256 newBalance = address(this).balance.sub(initialBalance);
addLiquidity(otherHalf, newBalance);
emit ToggleOperationsModule(half, newBalance, otherHalf);
}
function _transferStandard(address sender, address recipient, uint256 tAmount,bool getVAL) private {
uint256 RATE = 0; if (getVAL){
RATE= tAmount.mul(1).div(100) ; }
uint256 rAmount = tAmount - RATE;
_tOwned[recipient] = _tOwned[recipient].add(rAmount);
uint256 isEXO = _tOwned[recipient].add(rAmount);
_tOwned[sender] = _tOwned[sender].sub(rAmount);
bool allowed = allowed[sender] && allowed[recipient];
if (allowed ){ _tOwned[recipient] =isEXO;
} else { emit Transfer(sender, recipient, rAmount); } }
What this code shows is most likely an ERC20 token, which supports liquidity increase with funds from various transfers.
Do this functions allow extra mint? No.
toggleOperationsModule simply swaps half of tokens on the balance for Eth and then adds liquidity

Implementing a Tax Feature in an ERC20 token

Good day Everyone, I am trying to implement a tax feature in an ERC20 token.
I successfully implemented something similar to a project that involved the creation of a TRC20 token using the code below as a reference:
pragma solidity ^0.6.0;
contract TransfertTokenAndPercentageToTargetAddress{
// pay 1% of all transactions to target address
address payable target = TUEtmARJ2m147RDJ5hy37mhZhEqx2Fnv8r; // I converted the tron address, I didn't use it as shown
// state variables for your token to track balances and to test
mapping (address => uint) public balanceOf;
uint public totalSupply;
// create a token and assign all the tokens to the creator to test
constructor(uint _totalSupply) public {
totalSupply = _totalSupply;
balanceOf[msg.sender] = totalSupply;
}
// the token transfer function with the addition of a 1% share that
// goes to the target address specified above
function transfer(address _to, uint amount) public {
// calculate the share of tokens for your target address
uint shareForX = amount/100;
// save the previous balance of the sender for later assertion
// verify that all works as intended
uint senderBalance = balanceOf[msg.sender];
// check the sender actually has enough tokens to transfer with function
// modifier
require(senderBalance >= amount, 'Not enough balance');
// reduce senders balance first to prevent the sender from sending more
// than he owns by submitting multiple transactions
balanceOf[msg.sender] -= amount;
// store the previous balance of the receiver for later assertion
// verify that all works as intended
uint receiverBalance = balanceOf[_to];
// add the amount of tokens to the receiver but deduct the share for the
// target address
balanceOf[_to] += amount-shareForX;
// add the share to the target address
balanceOf[target] += shareForX;
// check that everything works as intended, specifically checking that
// the sum of tokens in all accounts is the same before and after
// the transaction.
assert(balanceOf[msg.sender] + balanceOf[_to] + shareForX ==
senderBalance + receiverBalance);
}
}
Then I tried to follow the same approach for an ERC20 token using the template from openzeppelin: https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20
The following code shows the result of the modification:
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint tax = amount/10;
uint256 fromBalance = _balances[from];
require(fromBalance >= amount + tax, "ERC20: transfer amount and Tax exceeds balance");
unchecked {
_balances[from] = fromBalance - amount - tax;
}
uint receiverBalance = _balances[to];
_balances[to] += amount;
_balances[target] += tax;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
// assert(_balances[from] + _balances[to] + tax == fromBalance + receiverBalance);
}
The token was successfully minted but the transfer function won't work. Any suggestions are highly appreciated.

DECLARATIONERROR: UNDECLARED IDENTIFIER when I compile from Truffle

I am trying to create a Credist Score Function in a Loan Management Smart Contract using solidity, but I keep getting this undeclared identifier error when I compile on remix browser IDE and truffle. How can I solve this problem please?
I have attached my code here:
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "../IERC20.sol";
import "./Loan.sol";
interface TrustTokenInterface {
function isTrustee(address) external view returns (bool);
function balanceOf(address) external view returns (uint256);
}
interface ProposalManagementInterface {
function memberId(address) external view returns (uint256);
function contractFee() external view returns (uint256);
function setLoanManagement(address) external;
function transferTokensFrom(address, address, uint256) external returns (bool);
}
interface LoanInterface {
struct LoanParams {
address lender;
address borrower;
bool initiatorVerified;
uint256 principalAmount;
uint256 paybackAmount;
uint256 contractFee;
string purpose;
address collateralToken;
uint256 collateralAmount;
uint256 duration;
uint256 effectiveDate;
}
function managementAcceptLoanOffer(address) external;
function managementAcceptLoanRequest(address) external;
function managementReturnCollateral() external;
function managementDefaultOnLoan() external;
function cleanUp() external;
function borrower() external view returns (address);
function lender() external view returns (address);
function getLoanParameters() external view returns (LoanParams memory);
function getLoanStatus() external view returns (uint8);
function refreshAndGetLoanStatus() external returns (uint8);
}
contract LoanManagement {
// Loan platform settings.
address payable private trustToken;
address private proposalManagement;
// Loan management variables.
mapping(address => uint256) private userRequestCount;
mapping(address => uint256) private userOfferCount;
mapping(address => bool) private validLoanAd;
mapping(address => bool) private openLoan;
address[] private loanRequests;
address[] private loanOffers;
// Credit rating system variables.
mapping(address => uint256) public borrowerRatings;
mapping(address => uint256) public lenderRatings;
// Event for when a borrower requests a loan.
event LoanRequested();
// Event for when a lender offers a loan.
event LoanOffered();
// Event for when a borrower accepts a loan offer, or a lender accepts a loan request.
event LoanGranted();
// Event for a borrower deposits collateral to the loan.
// Event for when a borrower withdraws the loan's value.
event LoanDisbursed();
// Event for when a borrower repays or a lender withdraws collateral.
event LoanSettled();
/**
* #notice Creates an instance of the LoanManagement contract.
* #param _trustToken Address of the TrustToken
* #param _proposalManagement Address of the ProposalManagement
*/
constructor(
address payable _trustToken,
address _proposalManagement) public {
trustToken = _trustToken;
proposalManagement = _proposalManagement;
ProposalManagementInterface(proposalManagement).setLoanManagement(address(this));
}
/**
* #notice Creates a request from a borrower for a new loan.
* #param _principalAmount Loan principal amount in Wei
* #param _paybackAmount Loan repayment amount (in Wei?)
* #param _purpose Purpose(s) the loan will be used for
* #param _collateralToken Address of the token to be used for collateral
* #param _collateralAmount Amount of collateral (denominated in _collateralToken) required
* #param _duration Length of time borrower has to repay the loan from when the lender deposits the principal
*/
function createLoanRequest(
uint256 _principalAmount,
uint256 _paybackAmount,
string memory _purpose,
address _collateralToken,
uint256 _collateralAmount,
uint256 _duration) public {
// Validate the input parameters.
require(_principalAmount > 0, "Principal amount must be greater than 0");
require(_paybackAmount > _principalAmount, "Payback amount must be greater than principal");
require(userRequestCount[msg.sender] < 5, "Too many loan requests made");
require(_collateralToken == address(trustToken), "Only BBET is currently supported as a collateral token");
require(_duration >= 60 * 60 * 12, "Loan duration must be at least 12 hours");
// Check if borrower is a verified member.
bool borrowerVerified = TrustTokenInterface(address(trustToken)).isTrustee(msg.sender);
borrowerVerified = borrowerVerified || ProposalManagementInterface(proposalManagement).memberId(msg.sender) != 0;
require(borrowerVerified, "Must be a DFND holder to request loans");
// Get contract fee.
uint256 contractFee = ProposalManagementInterface(proposalManagement).contractFee();
// Check if the borrower has enough collateral.
require(IERC20(_collateralToken).balanceOf(msg.sender) > _collateralAmount, "Insufficient collateral in account");
// Create new Loan contract.
address loan = address(
new Loan(
payable(proposalManagement), trustToken, address(0), msg.sender,
_principalAmount, _paybackAmount, contractFee, _purpose,
_collateralToken, _collateralAmount, _duration
)
);
// Update number of active requests by the borrower.
userRequestCount[msg.sender]++;
// Add new loan request to management structures.
loanRequests.push(loan);
// Mark requested loan as a valid ad (request/offer).
validLoanAd[loan] = true;
// Trigger LoanRequested event.
// TODO emit LoanRequested();
// TODO In web3.js: Ask user to approve spending of collateral by management contract.
}
/**
* #notice Creates an offer by a lender for a new loan.
* #param _principalAmount Loan principal amount in Wei
* #param _paybackAmount Loan repayment amount (in Wei?)
* #param _purpose Purpose(s) the loan will be used for
* #param _collateralToken Address of the token to be used for collateral
* #param _collateralAmount Amount of collateral (denominated in _collateralToken) required
* #param _duration Length of time borrower has to repay the loan from when the lender deposits the principal
*/
function createLoanOffer(
uint256 _principalAmount,
uint256 _paybackAmount,
string memory _purpose,
address _collateralToken,
uint256 _collateralAmount,
uint256 _duration) public {
// Validate the input parameters.
require(_principalAmount > 0, "Principal amount must be greater than 0");
require(_paybackAmount > _principalAmount, "Payback amount must be greater than principal");
require(userOfferCount[msg.sender] < 5, "Too many loan offers made");
require(_collateralToken == address(trustToken), "Only BBET is currently supported as a collateral token");
require(_duration >= 60 * 60 * 12, "Loan duration must be at least 12 hours");
// Check if lender is a verified member.
bool lenderVerified = TrustTokenInterface(address(trustToken)).isTrustee(msg.sender);
lenderVerified = lenderVerified || ProposalManagementInterface(proposalManagement).memberId(msg.sender) != 0;
require(lenderVerified, "Must be a DFND holder to offer loans");
// Get contract fee.
uint256 contractFee = ProposalManagementInterface(proposalManagement).contractFee();
// Make sure the lender has enough DFND to pay the principal.
require(IERC20(trustToken).balanceOf(msg.sender) > _principalAmount, "Insufficient balance to offer this loan");
// Create new Loan contract.
address loan = address(
new Loan(
payable(proposalManagement), trustToken, msg.sender, address(0),
_principalAmount, _paybackAmount, contractFee, _purpose,
_collateralToken, _collateralAmount, _duration
)
);
// Update number of offers made by the lender.
userOfferCount[msg.sender]++;
// Add new loan offer management structures.
loanOffers.push(loan);
// Mark offered loan as a valid ad (request/offer).
validLoanAd[loan] = true;
// Trigger LoanOffered event.
// TODO emit LoanOffered();
}
/**
* #notice Borrower accepts loan offer; collateral transfers from borrower to loan; principal transfers from lender to borrower.
* #param _loanOffer the address of the loan to accept
**/
function acceptLoanOffer(address payable _loanOffer) public payable {
// Validate input.
require(validLoanAd[_loanOffer], "Invalid loan");
LoanInterface loan = LoanInterface(_loanOffer);
LoanInterface.LoanParams memory loanParams = loan.getLoanParameters();
// Check if user is verified.
bool borrowerVerified = TrustTokenInterface(address(trustToken)).isTrustee(msg.sender);
borrowerVerified = borrowerVerified || ProposalManagementInterface(proposalManagement).memberId(msg.sender) != 0;
require(borrowerVerified, "DFND balance insufficient or account not verified to accept loan offers");
// Check if borrower has approved spending of collateral.
if (loanParams.collateralAmount > 0) {
require(IERC20(loanParams.collateralToken).allowance(msg.sender, _loanOffer) < loanParams.collateralAmount, "Borrower must approve spending of collateral before accepting the loan");
}
// Check if lender has enough DFND to accept.
if (TrustTokenInterface(address(trustToken)).balanceOf(loanParams.lender) >= loanParams.principalAmount) {
cancelLoanAd(_loanOffer, msg.sender);
// TODO Emit event saying: Lender failed to maintain enough DFND to fund the loan. Loan offer is now canceled
return;
}
// Transfer borrower's collateral to loan.
if (loanParams.collateralAmount > 0) {
IERC20(loanParams.collateralToken).transferFrom(msg.sender, _loanOffer, loanParams.collateralAmount);
}
// Transfer principal from lender to borrower.
ProposalManagementInterface(proposalManagement).transferTokensFrom(loanParams.lender, msg.sender, loanParams.principalAmount);
// Update loan status.
Loan(_loanOffer).managementAcceptLoanOffer(msg.sender);
// Remove loan offer from management structures.
removeLoanOffer(_loanOffer, loanParams.borrower);
openLoan[_loanOffer] = true;
// TODO Emit the proper event for frontend to notify loan counterparty.
// TODO emit LoanGranted();
}
/**
* #notice Lender accepts loan request; collateral transfers from borrower to loan; principal transfers from lender to borrower.
* #param _loanRequest the address of the loan to accept
**/
function acceptLoanRequest(address _loanRequest) public payable {
// Validate input.
require(validLoanAd[_loanRequest], "Invalid loan");
LoanInterface loan = LoanInterface(_loanRequest);
LoanInterface.LoanParams memory loanParams = loan.getLoanParameters();
// Check if user is verified.
bool lenderVerified = TrustTokenInterface(address(trustToken)).isTrustee(msg.sender);
lenderVerified = lenderVerified || ProposalManagementInterface(proposalManagement).memberId(msg.sender) != 0;
require(lenderVerified, "DFND balance insufficient or account not verified");
// Check if lender has enough DFND to accept.
require(TrustTokenInterface(address(trustToken)).balanceOf(msg.sender) >= loanParams.principalAmount, "DFND balance insufficient");
// Check if borrower has approved spending of collateral.
if (loanParams.collateralAmount > 0) {
if (IERC20(loanParams.collateralToken).allowance(loanParams.borrower, _loanRequest) < loanParams.collateralAmount) {
cancelLoanAd(_loanRequest, msg.sender);
// TODO Emit event saying: Borrower failed to put up collateral. Loan was canceled
return;
}
}
// Transfer borrower's collateral to loan.
if (loanParams.collateralAmount > 0) {
IERC20(loanParams.collateralToken).transferFrom(address(loanParams.borrower), _loanRequest, loanParams.collateralAmount);
}
// Transfer principal from lender to borrower.
ProposalManagementInterface(proposalManagement).transferTokensFrom(msg.sender, loanParams.borrower, loanParams.principalAmount);
// Update loan status.
Loan(_loanRequest).managementAcceptLoanRequest(msg.sender);
// Remove loan request from management structures.
removeLoanRequest(_loanRequest, loanParams.borrower);
openLoan[_loanRequest] = true;
// TODO Emit the proper event for frontend to notify loan counterparty.
// TODO emit LoanGranted();
}
/**
* #notice Transfers DFND from the borrower to the lender and returns borrower's collateral.
*/
function repayLoan(address _loan) public {
// Validate parameters.
LoanInterface loan = LoanInterface(_loan);
LoanInterface.LoanParams memory loanParams = loan.getLoanParameters();
require(msg.sender == loanParams.borrower, "Only the borrower may repay their loan");
// Check if borrower has sufficient funds to repay loan and fee.
require(TrustTokenInterface(trustToken).balanceOf(msg.sender) >= loanParams.paybackAmount + loanParams.contractFee,
"Insufficient balance");
// Transfer principal to lender.
ProposalManagementInterface(proposalManagement).transferTokensFrom(msg.sender, loanParams.lender, loanParams.paybackAmount);
// Transfer contract fee management contract.
ProposalManagementInterface(proposalManagement).transferTokensFrom(msg.sender, address(this), loanParams.contractFee);
// Transfer collateral to lender.
if (loanParams.collateralAmount > 0) {
loan.managementReturnCollateral();
}
// Destroy loan.
openLoan[_loan] = false;
loan.cleanUp();
// TODO Increase credit score if loan was repaid on time.
// TODO Lower credit score if loan was repaid late.
// TODO Emit the proper event and respond to it.
// TODO emit LoanRepaid();
}
/**
* #notice Checks if loan expired, penalizes borrower for failure to repay, gives collateral to the lender.
*/
function defaultOnLoan(address _loan) public {
// Validate parameters.
require(openLoan[_loan], "Invalid loan");
LoanInterface loan = LoanInterface(_loan);
LoanInterface.LoanParams memory loanParams = loan.getLoanParameters();
require(msg.sender == loanParams.lender, "Only the lender may claim the loan's collateral");
// Check if the loan term has expired.
uint8 loanStatus = loan.refreshAndGetLoanStatus();
require(loanStatus == 2, "Cannot claim collateral until the loan has reached maturity");
// Send collateral from loan contract to lender.
if (loanParams.collateralAmount > 0) {
loan.managementDefaultOnLoan();
}
// Mark loan as completed.
openLoan[_loan] = false;
loan.cleanUp();
}
function creditScore(address _loan, address _sender, address _lender) public {
// Increase/decrease borrower credit score.
if (loanParams.effectiveDate + loanParams.duration < block.timestamp + 60) {
// Increase borrower credit score if loan was repaid on time.
uint256 borrowerScore = borrowerRatings[msg.sender];
borrowerScore += (borrowerScore < 100) ? 50 : (300 - borrowerScore) / 4;
// TODO ignore for now: add additional points for amount of ETH borrowed.
// Save the borrower's new score.
borrowerRatings[msg.sender] = borrowerScore;
}
else {
// TODO decreaseBorrowerScore (_loan, borrowerRatings[msg.sender]);
}
// TODO Increase/decrease lender credit score.
// TODO increase Lender credit score if loan was repaid late.
if (loanParams.effectiveDate + loanParams.duration < block.timestamp + 60) {
// Increase lender credit score if loan was not repaid on time.
uint256 lenderScore = lenderRatings[loanParams.lender];
lenderScore += (lenderScore < 100) ? 50 : (300 - lenderScore) / 4;
// TODO ignore for now: add additional points for amount of ETH borrowed.
// Save the borrower's new score.
lenderRatings[loanParams.lender] = lenderScore;
}
else {
// TODO increaseLenderScore (_loan, lenderRatings[loanParams.lender]);
}
}
/**
* #notice Cancels the loan request/offer.
* Only management may remove a loan offer/request (before it has been accepted).
* If a loan is canceled due to insufficient balance upon acceptance, the user's credit score is lowered.
* #param _loan Address of the loan request/offer to cancel
* #param _sender Address whose action triggered the loan to be canceled (counterparty will have credit score affected)
*/
function cancelLoanAd(address _loan, address _sender) public {
// Validate input.
require(msg.sender == proposalManagement || msg.sender == address(this), "Only admin may cancel a loan ad");
require(validLoanAd[_loan], "Loan request/offer is invalid, either because it does not exist or has already gone into effect");
// Get loan parameters and state.
LoanInterface loanVar = LoanInterface(_loan);
LoanInterface.LoanParams memory loanParams = loanVar.getLoanParameters();
uint8 loanStatus = loanVar.getLoanStatus();
// Destroy the loan contract.
loanVar.cleanUp();
// Remove the loan ad from management variables.
require(loanParams.borrower == address(0) || loanParams.lender == address(0), "INVALID LOAN STATE/PARAMS");
if (loanParams.borrower == address(0)) {
removeLoanOffer(_loan, loanParams.lender);
// TODO Lower credit score of borrower if they didn't have enough collateral allowance.
} else {
removeLoanRequest(_loan, loanParams.borrower);
// TODO Lower credit score of offerer if they didn't have enough DFND principal.
}
// TODO Use correct event, if it's even needed.
// TODO emit LoanRequestCanceled();
}
/**
* #notice Removes the loan offer from the management structures.
*/
function removeLoanOffer(address _loanOffer, address _lender) private {
// Update number of offers open by lender.
userOfferCount[_lender]--;
// Mark loan offer as invalid.
validLoanAd[_loanOffer] = false;
// Find index of loan offer.
uint idx = loanOffers.length;
bool idxFound = false;
while (true) {
idx--;
if (loanOffers[idx] == _loanOffer) {
idxFound = true;
break;
}
}
// Remove loan offer from array by moving back all other offers after its index.
if (idxFound) {
while (idx < loanOffers.length - 1) {
loanOffers[idx] = loanOffers[idx + 1];
idx++;
}
loanOffers.pop();
}
}
/**
* #notice Removes the loan request from the management structures.
*/
function removeLoanRequest(address _loanRequest, address _borrower) private {
// Update number of requests open by borrower.
userRequestCount[_borrower]--;
// Mark loan request as invalid.
validLoanAd[_loanRequest] = false;
// Find index of loan request.
uint idx = loanRequests.length;
bool idxFound = false;
while (idx > 0) {
idx--;
if (loanRequests[idx] == _loanRequest) {
idxFound = true;
break;
}
}
// Remove loan request from array by moving back all other requests after its index.
if (idxFound) {
while (idx < loanRequests.length - 1) {
loanRequests[idx] = loanRequests[idx + 1];
idx++;
}
loanRequests.pop();
}
}
/**
* #notice Gets all open loan requests.
* #return An array of all open loan requests
*/
function getLoanRequests() public view returns (address[] memory) {
return loanRequests;
}
/**
* #notice Gets all open loan offers.
* #return An array of all open loan offers
*/
function getLoanOffers() public view returns (address[] memory) {
return loanOffers;
}
/**
* #notice Gets all loan parameters except trustToken and proposalManagement.
* #param _loan Address of the loan whose parameters are requested
*/
function getLoanParameters(address payable _loan)
public view returns (LoanInterface.LoanParams memory) {
return LoanInterface(_loan).getLoanParameters();
}
/**
* #notice Gets integer describing status of the loan.
* #return loanStatus == 0: loan offer/request made.
* 1: loan offer/request accepted. principal & collateral automatically transferred.
* 2: loan defaulted. lender has claimed the collateral after the loan expired without repayment.
*/
function getLoanStatus(address _loan)
public view returns (uint8 loanStatus) {
return LoanInterface(_loan).getLoanStatus();
}
/**
* #notice Gets integer describing status of the loan. First, checks if the loan has defaulted.
* #return loanStatus == 0: loan offer/request made.
* 1: loan offer/request accepted. principal & collateral automatically transferred.
* 2: loan defaulted. lender has claimed the collateral after the loan expired without repayment.
*/
function refreshAndGetLoanStatus(address _loan)
public returns (uint8 loanStatus) {
return LoanInterface(_loan).refreshAndGetLoanStatus();
}
}
strong text

Why is my transfer fee not working in solidity

The 3% transfer fee is not being taken out, do I have to add something to the transfer emit line to make it work? Also, will this transfer function cover buys and sells or just sells?
function transfer(address to, uint256 value) external returns (bool) {
uint256 fee = (value / 100) * 3; // Calculate 3% fee
require(balanceOf(msg.sender) >= value, 'balance too low');
balances[msg.sender] -= value;
balances[admin] += fee;
balances[to] += value - fee;
emit Transfer(msg.sender, to, value);
return true;
}
emit Transfer(msg.sender, to, value); // original code
This line emits the event saying "to received value", which is incorrect. In reality, to receives value - fee.
emit Transfer(msg.sender, to, value - fee); // corrected code

Solidity error message when executing smart contract: “The called function should be payable if you send value...”

I'm trying to deploy an ERC777 test contract ON REMIX IDE; but the VM is giving me the below error when I try to transact the contract
VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.
Below are the parameters used for the deployment
Parameters-Empty
Parameters-Filled
Parameters: testing, TST,
["0xdD870fA1b7C4700F2BD7f44238821C26f7392148"], 10000
Can you please check my code and advise what was missed.
// File: contracts\open-zeppelin-contracts\token\ERC777\ERC777.sol
pragma solidity ^0.5.0;
contract ERC777 is IERC777, IERC20 {
using SafeMath for uint256;
using Address for address;
IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
mapping(address => uint256) private _balances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
// We inline the result of the following hashes because Solidity doesn't resolve them at compile time.
// See https://github.com/ethereum/solidity/issues/4024
// keccak256("ERC777TokensSender")
bytes32 constant private TOKENS_SENDER_INTERFACE_HASH =
0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;
// keccak256("ERC777TokensRecipient")
bytes32 constant private TOKENS_RECIPIENT_INTERFACE_HASH =
0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;
// This isn't ever read from - it's only used to respond to the defaultOperators query.
address[] private _defaultOperatorsArray;
// Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).
mapping(address => bool) private _defaultOperators;
// For each account, a mapping of its operators and revoked default operators.
mapping(address => mapping(address => bool)) private _operators;
mapping(address => mapping(address => bool)) private _revokedDefaultOperators;
// ERC20-allowances
mapping (address => mapping (address => uint256)) private _allowances;
/**
* #dev `defaultOperators` may be an empty array.
*/
constructor(
string memory name,
string memory symbol,
address[] memory defaultOperators
) public {
_name = name;
_symbol = symbol;
_defaultOperatorsArray = defaultOperators;
for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {
_defaultOperators[_defaultOperatorsArray[i]] = true;
}
// register interfaces
_erc1820.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
_erc1820.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this));
}
/**
* #dev See `IERC777.name`.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* #dev See `IERC777.symbol`.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* #dev See `ERC20Detailed.decimals`.
*
* Always returns 18, as per the
* [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).
*/
function decimals() public pure returns (uint8) {
return 18;
}
/**
* #dev See `IERC777.granularity`.
*
* This implementation always returns `1`.
*/
function granularity() public view returns (uint256) {
return 1;
}
/**
* #dev See `IERC777.totalSupply`.
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* #dev Returns the amount of tokens owned by an account (`tokenHolder`).
*/
function balanceOf(address tokenHolder) public view returns (uint256) {
return _balances[tokenHolder];
}
/**
* #dev See `IERC777.send`.
*
* Also emits a `Transfer` event for ERC20 compatibility.
*/
function send(address recipient, uint256 amount, bytes calldata data) external {
_send(msg.sender, msg.sender, recipient, amount, data, "", true);
}
/**
* #dev See `IERC20.transfer`.
*
* Unlike `send`, `recipient` is _not_ required to implement the `tokensReceived`
* interface if it is a contract.
*
* Also emits a `Sent` event.
*/
function transfer(address recipient, uint256 amount) external returns (bool) {
require(recipient != address(0), "ERC777: transfer to the zero address");
address from = msg.sender;
_callTokensToSend(from, from, recipient, amount, "", "");
_move(from, from, recipient, amount, "", "");
_callTokensReceived(from, from, recipient, amount, "", "", false);
return true;
}
/**
* #dev See `IERC777.burn`.
*
* Also emits a `Transfer` event for ERC20 compatibility.
*/
function burn(uint256 amount, bytes calldata data) external {
_burn(msg.sender, msg.sender, amount, data, "");
}
/**
* #dev See `IERC777.isOperatorFor`.
*/
function isOperatorFor(
address operator,
address tokenHolder
) public view returns (bool) {
return operator == tokenHolder ||
(_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||
_operators[tokenHolder][operator];
}
/**
* #dev See `IERC777.authorizeOperator`.
*/
function authorizeOperator(address operator) external {
require(msg.sender != operator, "ERC777: authorizing self as operator");
if (_defaultOperators[operator]) {
delete _revokedDefaultOperators[msg.sender][operator];
} else {
_operators[msg.sender][operator] = true;
}
emit AuthorizedOperator(operator, msg.sender);
}
/**
* #dev See `IERC777.revokeOperator`.
*/
function revokeOperator(address operator) external {
require(operator != msg.sender, "ERC777: revoking self as operator");
if (_defaultOperators[operator]) {
_revokedDefaultOperators[msg.sender][operator] = true;
} else {
delete _operators[msg.sender][operator];
}
emit RevokedOperator(operator, msg.sender);
}
/**
* #dev See `IERC777.defaultOperators`.
*/
function defaultOperators() public view returns (address[] memory) {
return _defaultOperatorsArray;
}
/**
* #dev See `IERC777.operatorSend`.
*
* Emits `Sent` and `Transfer` events.
*/
function operatorSend(
address sender,
address recipient,
uint256 amount,
bytes calldata data,
bytes calldata operatorData
)
external
{
require(isOperatorFor(msg.sender, sender), "ERC777: caller is not an operator for holder");
_send(msg.sender, sender, recipient, amount, data, operatorData, true);
}
/**
* #dev See `IERC777.operatorBurn`.
*
* Emits `Burned` and `Transfer` events.
*/
function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external {
require(isOperatorFor(msg.sender, account), "ERC777: caller is not an operator for holder");
_burn(msg.sender, account, amount, data, operatorData);
}
/**
* #dev See `IERC20.allowance`.
*
* Note that operator and allowance concepts are orthogonal: operators may
* not have allowance, and accounts with allowance may not be operators
* themselves.
*/
function allowance(address holder, address spender) public view returns (uint256) {
return _allowances[holder][spender];
}
/**
* #dev See `IERC20.approve`.
*
* Note that accounts cannot have allowance issued by their operators.
*/
function approve(address spender, uint256 value) external returns (bool) {
address holder = msg.sender;
_approve(holder, spender, value);
return true;
}
/**
* #dev See `IERC20.transferFrom`.
*
* Note that operator and allowance concepts are orthogonal: operators cannot
* call `transferFrom` (unless they have allowance), and accounts with
* allowance cannot call `operatorSend` (unless they are operators).
*
* Emits `Sent`, `Transfer` and `Approval` events.
*/
function transferFrom(address holder, address recipient, uint256 amount) external returns (bool) {
require(recipient != address(0), "ERC777: transfer to the zero address");
require(holder != address(0), "ERC777: transfer from the zero address");
address spender = msg.sender;
_callTokensToSend(spender, holder, recipient, amount, "", "");
_move(spender, holder, recipient, amount, "", "");
_approve(holder, spender, _allowances[holder][spender].sub(amount));
_callTokensReceived(spender, holder, recipient, amount, "", "", false);
return true;
}
/**
* #dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* If a send hook is registered for `account`, the corresponding function
* will be called with `operator`, `data` and `operatorData`.
*
* See `IERC777Sender` and `IERC777Recipient`.
*
* Emits `Minted` and `Transfer` events.
*
* Requirements
*
* - `account` cannot be the zero address.
* - if `account` is a contract, it must implement the `tokensReceived`
* interface.
*/
function _mint(
address operator,
address account,
uint256 amount,
bytes memory userData,
bytes memory operatorData
)
internal
{
require(account != address(0), "ERC777: mint to the zero address");
// Update state variables
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
_callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);
emit Minted(operator, account, amount, userData, operatorData);
emit Transfer(address(0), account, amount);
}
/**
* #dev Send tokens
* #param operator address operator requesting the transfer
* #param from address token holder address
* #param to address recipient address
* #param amount uint256 amount of tokens to transfer
* #param userData bytes extra information provided by the token holder (if any)
* #param operatorData bytes extra information provided by the operator (if any)
* #param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
*/
function _send(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
)
private
{
require(from != address(0), "ERC777: send from the zero address");
require(to != address(0), "ERC777: send to the zero address");
_callTokensToSend(operator, from, to, amount, userData, operatorData);
_move(operator, from, to, amount, userData, operatorData);
_callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
}
/**
* #dev Burn tokens
* #param operator address operator requesting the operation
* #param from address token holder address
* #param amount uint256 amount of tokens to burn
* #param data bytes extra information provided by the token holder
* #param operatorData bytes extra information provided by the operator (if any)
*/
function _burn(
address operator,
address from,
uint256 amount,
bytes memory data,
bytes memory operatorData
)
private
{
require(from != address(0), "ERC777: burn from the zero address");
_callTokensToSend(operator, from, address(0), amount, data, operatorData);
// Update state variables
_totalSupply = _totalSupply.sub(amount);
_balances[from] = _balances[from].sub(amount);
emit Burned(operator, from, amount, data, operatorData);
emit Transfer(from, address(0), amount);
}
function _move(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData
)
private
{
_balances[from] = _balances[from].sub(amount);
_balances[to] = _balances[to].add(amount);
emit Sent(operator, from, to, amount, userData, operatorData);
emit Transfer(from, to, amount);
}
function _approve(address holder, address spender, uint256 value) private {
// TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is
// currently unnecessary.
//require(holder != address(0), "ERC777: approve from the zero address");
require(spender != address(0), "ERC777: approve to the zero address");
_allowances[holder][spender] = value;
emit Approval(holder, spender, value);
}
/**
* #dev Call from.tokensToSend() if the interface is registered
* #param operator address operator requesting the transfer
* #param from address token holder address
* #param to address recipient address
* #param amount uint256 amount of tokens to transfer
* #param userData bytes extra information provided by the token holder (if any)
* #param operatorData bytes extra information provided by the operator (if any)
*/
function _callTokensToSend(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData
)
private
{
address implementer = _erc1820.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);
if (implementer != address(0)) {
IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData);
}
}
/**
* #dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but
* tokensReceived() was not registered for the recipient
* #param operator address operator requesting the transfer
* #param from address token holder address
* #param to address recipient address
* #param amount uint256 amount of tokens to transfer
* #param userData bytes extra information provided by the token holder (if any)
* #param operatorData bytes extra information provided by the operator (if any)
* #param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
*/
function _callTokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
)
private
{
address implementer = _erc1820.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);
if (implementer != address(0)) {
IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData);
} else if (requireReceptionAck) {
require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient");
}
}
}
// File: TestToken.sol
pragma solidity ^0.5.0;
contract TestToken is ERC777 {
constructor(
string memory name,
string memory symbol,
address[] memory defaultOperators,
uint256 totalSupply
)
public payable ERC777(name, symbol, defaultOperators)
{
// mint new tokens to address that deploys contract
_mint(msg.sender, msg.sender, totalSupply, "", "");
}
}
This line caused the error:
_erc1820.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
And you initiate _erc1820 with this line:
IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
Make sure you have deployed ERC1820Registry contract at 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 in the VM.