За этот период ко мне присоединилось много друзей.、Мы все совещались по поводу похожей бизнес-сцены、 следующее:
Я спросил его, почему он просто не использовал стандартную функцию утверждения Token и не вызвал ее один раз заранее, а затем напрямую выполнил второй шаг. У них у всех были свои причины, и я не мог расспросить подробно.
Сначала объясните принцип реализации утверждения в стандартном контракте, и мы поймем, почему вызов test2 завершается неудачно;
И как его преобразовать, чтобы удовлетворить этим бизнес-требованиям.
Как правило, стандартные токены реализуют протокол IERC20.
IERC20
протокол/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
Все функции интерфейса здесь имеют одну особенность: все они состоят из external
Модифицировано.
Обычно всмарт-контрактсередина,external
Модификаторы используются для ограничения видимости и вызова методов. Когда метод помечен как external
, это означает, что метод можно вызвать только из внешних учетных записей (т. е. учетных записей, не являющихся смарт-контрактами). Это означает, что этот метод не может быть вызван напрямую другими методами в том же смарт-контракте или другими смарт-контрактами.
IERC20
Так、следующее
contract BEP20Token is Context, IERC20, Ownable {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
uint8 private _decimals;
string private _symbol;
string private _name;
constructor() public {
_name = " ";
_symbol =" " ;
_decimals = 18;
_totalSupply = 10000000 *10**18;
_balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
/**
* @dev Returns the bep token owner.
*/
function getOwner() external view returns (address) {
return owner();
}
/**
* @dev Returns the token decimals.
*/
function decimals() external view returns (uint8) {
return _decimals;
}
/**
* @dev Returns the token symbol.
*/
function symbol() external view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the token name.
*/
function name() external view returns (string memory) {
return _name;
}
/**
* @dev See {BEP20-totalSupply}.
*/
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
/**
* @dev See {BEP20-balanceOf}.
*/
function balanceOf(address account) external view returns (uint256) {
return _balances[account];
}
/**
* @dev See {BEP20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) external returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {BEP20-allowance}.
*/
function allowance(address owner, address spender) external view returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {BEP20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) external returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {BEP20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {BEP20};
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for `sender`'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "BEP20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {BEP20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {BEP20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "BEP20: decreased allowance below zero"));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is 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 {
require(sender != address(0), "BEP20: transfer from the zero address");
require(recipient != address(0), "BEP20: transfer to the zero address");
_balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal {
require(account != address(0), "BEP20: burn from the zero address");
_balances[account] = _balances[account].sub(amount, "BEP20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal {
require(owner != address(0), "BEP20: approve from the zero address");
require(spender != address(0), "BEP20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Destroys `amount` tokens from `account`.`amount` is then deducted
* from the caller's allowance.
*
* See {_burn} and {_approve}.
*/
function _burnFrom(address account, uint256 amount) internal {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "BEP20: burn amount exceeds allowance"));
}
}
Давайте посмотрим на стандартные функции в Token.
function test() public {
toekn.approve( address(this), 10000000000000000000);
}
Этапы выполнения
1. При внешнем вызове тестовой функции
2. Вызовите функцию еще раз. toekn.approve
3、в это времяtoeknизapprove
функцияпозвони еще раз _approve
(_msgSender(), spender, amount);
вот один _msgSender()
Функция, ключ, здесь. Когда контракт токена вызывается внешним контрактом, _msgSender()
Результат вызова самой функции: внешний контрактсобственный адрес!!!。
Многие студенты думают, что запуск внешних функций адрес, поэтому адрес отправителя авторизует токен на адрес контракта. Как всем известно, это внешний контракт Авторизоватьотдал Авторизоватьадрес。
К этому моменту большинство студентов поняли принцип, но... некоторые студенты вскоре спросили, в данном случае, почему бы нам просто не позвонить
_approve
функция, переданная напрямую наш Не лучше ли параметры...
Давайте посмотрим еще раз _approve
функция
internal
Роль модификаторовinternal
Методы могут быть вызваны только другими методами в пределах того же смарт-контракта.существоватьсмарт-контрактсередина,internal
Модификаторы используются для ограничения видимости и вызова методов. Когда метод помечен как internal
, это означает, что метод может быть вызван только другими методами в том же смарт-контракте. Это означает, что к методу не могут получить прямой доступ внешние учетные записи или вызовы из других смарт-контрактов.
Из этого видно _approve
Функция не поддерживает внешние вызовы, поэтому работать не будет.
Фактически, после приведенного выше объяснения по принципу、Трансформацияиз Суть заключается в предоставлении внешнихизapprove
функция。
function approve(address sendr,address spender, uint256 amount) external returns (bool) {
_approve(sendr, spender, amount);
return true;
}
Открыть функцию sendr для внешних вызовов
contract ArrayDeletionByMovingElements {
IERC20 public toekn;
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(IERC20 _token) {
toekn = _token;
}
function test() public {
toekn.approve( msg.sender,address(this), 10000000000000000000);
}
function test2() public {
toekn.transferFrom(msg.sender, address(this), 1000);
emit Transfer(msg.sender, address(this), 1000);
}
}
Однако все же рекомендуется принять форму внешней функции Авторизовать.,Не рекомендуется трансформировать стандартный токен... Лучше обратиться к общепринятым операционным процедурам на рынке.