• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Yчимся создавать смарт-контракты Ethereum на Solidity с самого начала и пока смерть не разлучит нас / #3 для любителей скам-контрактов

вавилонец

CPU register
Пользователь
Регистрация
17.06.2021
Сообщения
1 116
Реакции
1 265
День добрый!
Это даже не статья, а скорее всего заметка/помятка для любителей использовать халявные скам-смарт-контракты.
Почитал на нашем борде пару тем про скам токены, почитал код .sol файлов и почему то в обоих ститически указан адрес eth-кошелька, чего не должно быть - так как все ваши старания в виде n-количества эфира уйдут на на ваш кошель а прям в лапы гнусным падонкам) хы-хы-хы. По этому делюсь кодом с ПОДРОБНЫМи коментариями о том как должен быть построен токен IERC20, на котором основываются большинство / по крайней мере мною прочитанных/ кодов.

Код интерфеса который определяет основные функции токена на базе IERC20
Код:
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20 {
    function name() external view returns(string memory); //функция названия токена
    function symbol()  external view returns(string memory);  //краткое наименование токена
    function decimals() external pure returns(uint);//колличетво знаков после запятой
    function totalSuply() external view returns(uint); //колличество токенов в обороте
    function balanceOf(address account) external view returns(uint); //сколько токенов на том или ином аккаунте
    function transfer(address to, uint amount) external; // функция перевода средств на адреес to в колличестве amount
    function allowance(address _owner, address spender) external view returns(uint); // возможность забрать у нас (owner) токены третьему лицу (spender)
    function approve(address spender, uint amount) external;   //позволяет spender списать amount монет используя функцию allowance
    function transferFrom(address sender, address recipient, uint amount ) external; // функция отправки средств от sender к recipient в колличестве amount
    event Transfer(address indexed from, address indexed to, uint amount); //событие индексированной транзакции с адреса to на from, в колличестве amount
    event Approve(address indexed owner, address indexed to, uint amount); //событие подтверждения списания от owner к to
    
}


Код контрактов токена:

Код:
// spdx-License-Identifier: MIT

pragma solidity ^0.8.0;
import "./IERC20.sol";

contract ERC20 is IERC20 {
    uint totalTokens;  // сколько токенов начислено на данный момент
    address owner;      //адресс владельца
    mapping(address=>uint) balances; //учет количества токенов на балансе адреса
    mapping(address => mapping(address =>uint)) allowances; //информация о возможности списывания с кошеля на другой кошель
    string _name; //название токена
    string _symbol; //символ токена
    function name() external view returns(string memory){ //считывает имя токена и возвращает его
        return _name;
    }
    function symbol() external view returns(string memory){ //считывает символ токена и возвращает его
        return _symbol;
    }
    function decimals() external pure returns(uint){
        return 18;
    }
    function totalSuply() external view returns(uint){
        return totalTokens;
    }
    
    modifier enoughTokens(address _from, uint _amount) {   // проверка того что на балансе для списания есть $$
        require(balanceOf(_from) >= _amount, "not enough tokens!");
        _;
    }

    modifier onlyOwner() {                              //проверка собственности
        require(msg.sender == owner, "not an owner!");
        _;
    }

    constructor (string memory name_, string memory symbol_, uint initialSupply, address shop) { //имя, символ, сколько токенов изначально введено в оборот, адресс магазина по распространению токенов
        _name = name_;            //
        _symbol = symbol_;
        owner = msg.sender;
    }

    function balanceOf(address account) public view returns(uint){
        return balances[account]; //возвращает баланс аккаунта
    }
    function transfer(address to, uint amount) external enoughTokens(msg.sender, amount) { // перевод с кошелька инициатора транзакции to  на другой кошелек с проверкой есть ли $$
        _beforeTokenTransfer(msg.sender, to, amount); // проверка правильности адресов и колличества
        balances[msg.sender] -= amount; // забрал у себя
        balances[to] += amount;  // добавил получателя
        emit Transfer(msg.sender, to, amount); //инициализация события перевода $$
    }
    
    function mint( uint amount, address shop) public onlyOwner {  // ввод токенов в оборот и зачисление на адресс
        _beforeTokenTransfer(address(0), shop, amount);
        balances[shop] += amount; //на баланс магазина добавить amount токенов
        totalTokens += amount;  //контрлируем добавление токенов к вообщеначисленным токенам
        emit Transfer(address(0), shop, amount);  //порождение события отправки токенов на нулевого адреса в магазин в колличестве amount
    }

    function burn(address _from, uint amount) public onlyOwner enoughTokens(_from, amount) { // "сжигаем" лишние токены
        _beforeTokenTransfer(_from, address(0), amount);
        balances[_from] -= amount;
        totalTokens -= amount;
    }
    function allowance(address _owner, address spender) public view returns(uint){  //проверка может ли сторонний аккаунт списать $$ в свою пользу без моего разрешения
         return allowances[_owner][spender];
    }
    function approve (address spender, uint amount) public {  //кому и сколько я разрешаю забирать токенов
        _approve(msg.sender, spender, amount);
    }
    function _approve(address sender, address spender, amount) internal virtual { 
        allowances[sender][spender] = amount;
        emit Approve(sender, spender, amount); //порождение собыия Approve
    }

    function transferFrom(address sender, address recipient, uint amount ) external enoughTokens(sender, amount) { // функция забирает из sender отдает в recipient, проверка если ли у sender $$
        _beforeTokenTransfer(sender, recipient, amount);
        require(allowances[sender][recipient]) >= amount, "check allowance!");  // что у sender больше $$ чем amount, т.к. транзакция слетит если вернется отрицательное значение , потому что переменная uint -беззнаковая
        allowances[sender][recipient] -= amount;
        balances[sender] -= amount;
        balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }
// ниже написана функция выполняющаяся до перевода $$ для наибольше безопасности
    function _beforeTokenTransfer(
        address from,   //адрес откуда
        address to,     //адрес куда
        uint amount     // сколько
    ) internal virtual {}   //virtual используется для переопределения функции ниже по иерархии
}
// создаем новый контракт магазина youName
contract youName is ERC20 {
    constructor(address shop) ERC20 ("ERC20","ERC20", 100500100155, shop) { //обращается к конструктору в родительском контракте и передает ему значения
    }
contract youNameShop {    // контракт магазина токенов
    IERC20 public token;       // описывает взаимодействие с интерфейсом IERC20.sol
    address payable public owner;   // платежеспособный адрес собственника
    event Bought(uint _amount, address indexed _buyer); // событие покупки содержит сколько и адрес покупателя
    event Sold( uint _amount, address indexed _seller); // событие продажи, сколько и адрес продавца

    constructor(){
        token = new youName(address(this)); // new - операция развертывания стороннего смарт-контракта, по адресу нашего магазина (this)
        owner = payable(msg.sender); //делаем адресс owner сразу способным получать/переводить денюшку
    }   
    modifier onlyOwner() {                              //проверка собственности, только владелец может выводить деньги
        require(msg.sender == owner, "not an owner!");
        _;
    }
    function sell (uint _amountToSell) external {  // функция продажи токена
        require(
            _amountToSell > 0 &&   // проверка наличия токенов так как  totalTokens может закончится
            token.balanceOf(msg.sender) >= _amountToSell, "incorrect amount" // проверка наличия у покупателя средств для покупки запрашиваемого количества токенов
        );
        uint allowance = token.allowance(msg.sender, address(this)); 
        require(allowance >= _amountToSell, "check allowance!");      // проверка того что покупатель разрешил списать $$ с его счёта
        token.transferFrom(msg.sender. address(this), amountToSell); // при прохождении проверки магазан забирает оплату от покупателя
        payable(msg.sender).transfer(_amountToSell) // передача продавцу токенов его $$
        emit Sold(_amountToSell, msg.sender);  // событие продажи в количестве и кем продано
    }
    
    receive() external payable { // fallback - функция, принимающая средства от покупателей, вызывается автоматически если в контракт просто пришли $$ / типа просто перевод без вызова функции покупки/ продажи
        uint tokenToBuy = msg.value; // при покупке 1 token за 1 wai
        require(tokenToBuy > 0, "not enough funds"); // проверка количества покупаемых токенов

        uint currentBalance = tokenBalance(); //чтобы не получилось что токенов к продаже меньше чем токенов хочет покупатель
        require(currentBalance >= tokenToBuy, " not enough tokens!");

        token.transfer(msg.sender, tokenToBuy); // переводим токены тому кто запросил в необходимом колличестве
        emit Bought(tokenToBuy, msg.sender); // породили событие покупки
        
    }
    function tockenBalance() public view returns (uint){ //сколько на счету магазина есть токенов
        return tokenBalanceOf(address(this));   
    }
}

Функции скама в следующих заметках.
 
День добрый!
Это даже не статья, а скорее всего заметка/помятка для любителей использовать халявные скам-смарт-контракты.
Почитал на нашем борде пару тем про скам токены, почитал код .sol файлов и почему то в обоих ститически указан адрес eth-кошелька, чего не должно быть - так как все ваши старания в виде n-количества эфира уйдут на на ваш кошель а прям в лапы гнусным падонкам) хы-хы-хы. По этому делюсь кодом с ПОДРОБНЫМи коментариями о том как должен быть построен токен IERC20, на котором основываются большинство / по крайней мере мною прочитанных/ кодов.

Код интерфеса который определяет основные функции токена на базе IERC20
Код:
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20 {
    function name() external view returns(string memory); //функция названия токена
    function symbol()  external view returns(string memory);  //краткое наименование токена
    function decimals() external pure returns(uint);//колличетво знаков после запятой
    function totalSuply() external view returns(uint); //колличество токенов в обороте
    function balanceOf(address account) external view returns(uint); //сколько токенов на том или ином аккаунте
    function transfer(address to, uint amount) external; // функция перевода средств на адреес to в колличестве amount
    function allowance(address _owner, address spender) external view returns(uint); // возможность забрать у нас (owner) токены третьему лицу (spender)
    function approve(address spender, uint amount) external;   //позволяет spender списать amount монет используя функцию allowance
    function transferFrom(address sender, address recipient, uint amount ) external; // функция отправки средств от sender к recipient в колличестве amount
    event Transfer(address indexed from, address indexed to, uint amount); //событие индексированной транзакции с адреса to на from, в колличестве amount
    event Approve(address indexed owner, address indexed to, uint amount); //событие подтверждения списания от owner к to
   
}


Код контрактов токена:

Код:
// spdx-License-Identifier: MIT

pragma solidity ^0.8.0;
import "./IERC20.sol";

contract ERC20 is IERC20 {
    uint totalTokens;  // сколько токенов начислено на данный момент
    address owner;      //адресс владельца
    mapping(address=>uint) balances; //учет количества токенов на балансе адреса
    mapping(address => mapping(address =>uint)) allowances; //информация о возможности списывания с кошеля на другой кошель
    string _name; //название токена
    string _symbol; //символ токена
    function name() external view returns(string memory){ //считывает имя токена и возвращает его
        return _name;
    }
    function symbol() external view returns(string memory){ //считывает символ токена и возвращает его
        return _symbol;
    }
    function decimals() external pure returns(uint){
        return 18;
    }
    function totalSuply() external view returns(uint){
        return totalTokens;
    }
   
    modifier enoughTokens(address _from, uint _amount) {   // проверка того что на балансе для списания есть $$
        require(balanceOf(_from) >= _amount, "not enough tokens!");
        _;
    }

    modifier onlyOwner() {                              //проверка собственности
        require(msg.sender == owner, "not an owner!");
        _;
    }

    constructor (string memory name_, string memory symbol_, uint initialSupply, address shop) { //имя, символ, сколько токенов изначально введено в оборот, адресс магазина по распространению токенов
        _name = name_;            //
        _symbol = symbol_;
        owner = msg.sender;
    }

    function balanceOf(address account) public view returns(uint){
        return balances[account]; //возвращает баланс аккаунта
    }
    function transfer(address to, uint amount) external enoughTokens(msg.sender, amount) { // перевод с кошелька инициатора транзакции to  на другой кошелек с проверкой есть ли $$
        _beforeTokenTransfer(msg.sender, to, amount); // проверка правильности адресов и колличества
        balances[msg.sender] -= amount; // забрал у себя
        balances[to] += amount;  // добавил получателя
        emit Transfer(msg.sender, to, amount); //инициализация события перевода $$
    }
   
    function mint( uint amount, address shop) public onlyOwner {  // ввод токенов в оборот и зачисление на адресс
        _beforeTokenTransfer(address(0), shop, amount);
        balances[shop] += amount; //на баланс магазина добавить amount токенов
        totalTokens += amount;  //контрлируем добавление токенов к вообщеначисленным токенам
        emit Transfer(address(0), shop, amount);  //порождение события отправки токенов на нулевого адреса в магазин в колличестве amount
    }

    function burn(address _from, uint amount) public onlyOwner enoughTokens(_from, amount) { // "сжигаем" лишние токены
        _beforeTokenTransfer(_from, address(0), amount);
        balances[_from] -= amount;
        totalTokens -= amount;
    }
    function allowance(address _owner, address spender) public view returns(uint){  //проверка может ли сторонний аккаунт списать $$ в свою пользу без моего разрешения
         return allowances[_owner][spender];
    }
    function approve (address spender, uint amount) public {  //кому и сколько я разрешаю забирать токенов
        _approve(msg.sender, spender, amount);
    }
    function _approve(address sender, address spender, amount) internal virtual {
        allowances[sender][spender] = amount;
        emit Approve(sender, spender, amount); //порождение собыия Approve
    }

    function transferFrom(address sender, address recipient, uint amount ) external enoughTokens(sender, amount) { // функция забирает из sender отдает в recipient, проверка если ли у sender $$
        _beforeTokenTransfer(sender, recipient, amount);
        require(allowances[sender][recipient]) >= amount, "check allowance!");  // что у sender больше $$ чем amount, т.к. транзакция слетит если вернется отрицательное значение , потому что переменная uint -беззнаковая
        allowances[sender][recipient] -= amount;
        balances[sender] -= amount;
        balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }
// ниже написана функция выполняющаяся до перевода $$ для наибольше безопасности
    function _beforeTokenTransfer(
        address from,   //адрес откуда
        address to,     //адрес куда
        uint amount     // сколько
    ) internal virtual {}   //virtual используется для переопределения функции ниже по иерархии
}
// создаем новый контракт магазина youName
contract youName is ERC20 {
    constructor(address shop) ERC20 ("ERC20","ERC20", 100500100155, shop) { //обращается к конструктору в родительском контракте и передает ему значения
    }
contract youNameShop {    // контракт магазина токенов
    IERC20 public token;       // описывает взаимодействие с интерфейсом IERC20.sol
    address payable public owner;   // платежеспособный адрес собственника
    event Bought(uint _amount, address indexed _buyer); // событие покупки содержит сколько и адрес покупателя
    event Sold( uint _amount, address indexed _seller); // событие продажи, сколько и адрес продавца

    constructor(){
        token = new youName(address(this)); // new - операция развертывания стороннего смарт-контракта, по адресу нашего магазина (this)
        owner = payable(msg.sender); //делаем адресс owner сразу способным получать/переводить денюшку
    }  
    modifier onlyOwner() {                              //проверка собственности, только владелец может выводить деньги
        require(msg.sender == owner, "not an owner!");
        _;
    }
    function sell (uint _amountToSell) external {  // функция продажи токена
        require(
            _amountToSell > 0 &&   // проверка наличия токенов так как  totalTokens может закончится
            token.balanceOf(msg.sender) >= _amountToSell, "incorrect amount" // проверка наличия у покупателя средств для покупки запрашиваемого количества токенов
        );
        uint allowance = token.allowance(msg.sender, address(this));
        require(allowance >= _amountToSell, "check allowance!");      // проверка того что покупатель разрешил списать $$ с его счёта
        token.transferFrom(msg.sender. address(this), amountToSell); // при прохождении проверки магазан забирает оплату от покупателя
        payable(msg.sender).transfer(_amountToSell) // передача продавцу токенов его $$
        emit Sold(_amountToSell, msg.sender);  // событие продажи в количестве и кем продано
    }
   
    receive() external payable { // fallback - функция, принимающая средства от покупателей, вызывается автоматически если в контракт просто пришли $$ / типа просто перевод без вызова функции покупки/ продажи
        uint tokenToBuy = msg.value; // при покупке 1 token за 1 wai
        require(tokenToBuy > 0, "not enough funds"); // проверка количества покупаемых токенов

        uint currentBalance = tokenBalance(); //чтобы не получилось что токенов к продаже меньше чем токенов хочет покупатель
        require(currentBalance >= tokenToBuy, " not enough tokens!");

        token.transfer(msg.sender, tokenToBuy); // переводим токены тому кто запросил в необходимом колличестве
        emit Bought(tokenToBuy, msg.sender); // породили событие покупки
       
    }
    function tockenBalance() public view returns (uint){ //сколько на счету магазина есть токенов
        return tokenBalanceOf(address(this));  
    }
}

Функции скама в следующих заметках.
Привет думаешь пару месяцев хватит чтоб изучить Solidity и понимать Скам или нет.Планирую найти белую раб типа аудит или поиск багов в контрактах,есть советы?
 
Привет думаешь пару месяцев хватит чтоб изучить Solidity и понимать Скам или нет.Планирую найти белую раб типа аудит или поиск багов в контрактах,есть советы?
отписал ПМ
 
День добрый!
Это даже не статья, а скорее всего заметка/помятка для любителей использовать халявные скам-смарт-контракты.
Почитал на нашем борде пару тем про скам токены, почитал код .sol файлов и почему то в обоих ститически указан адрес eth-кошелька, чего не должно быть - так как все ваши старания в виде n-количества эфира уйдут на на ваш кошель а прям в лапы гнусным падонкам) хы-хы-хы. По этому делюсь кодом с ПОДРОБНЫМи коментариями о том как должен быть построен токен IERC20, на котором основываются большинство / по крайней мере мною прочитанных/ кодов.

Код интерфеса который определяет основные функции токена на базе IERC20
Код:
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IERC20 {
    function name() external view returns(string memory); //функция названия токена
    function symbol()  external view returns(string memory);  //краткое наименование токена
    function decimals() external pure returns(uint);//колличетво знаков после запятой
    function totalSuply() external view returns(uint); //колличество токенов в обороте
    function balanceOf(address account) external view returns(uint); //сколько токенов на том или ином аккаунте
    function transfer(address to, uint amount) external; // функция перевода средств на адреес to в колличестве amount
    function allowance(address _owner, address spender) external view returns(uint); // возможность забрать у нас (owner) токены третьему лицу (spender)
    function approve(address spender, uint amount) external;   //позволяет spender списать amount монет используя функцию allowance
    function transferFrom(address sender, address recipient, uint amount ) external; // функция отправки средств от sender к recipient в колличестве amount
    event Transfer(address indexed from, address indexed to, uint amount); //событие индексированной транзакции с адреса to на from, в колличестве amount
    event Approve(address indexed owner, address indexed to, uint amount); //событие подтверждения списания от owner к to
   
}


Код контрактов токена:

Код:
// spdx-License-Identifier: MIT

pragma solidity ^0.8.0;
import "./IERC20.sol";

contract ERC20 is IERC20 {
    uint totalTokens;  // сколько токенов начислено на данный момент
    address owner;      //адресс владельца
    mapping(address=>uint) balances; //учет количества токенов на балансе адреса
    mapping(address => mapping(address =>uint)) allowances; //информация о возможности списывания с кошеля на другой кошель
    string _name; //название токена
    string _symbol; //символ токена
    function name() external view returns(string memory){ //считывает имя токена и возвращает его
        return _name;
    }
    function symbol() external view returns(string memory){ //считывает символ токена и возвращает его
        return _symbol;
    }
    function decimals() external pure returns(uint){
        return 18;
    }
    function totalSuply() external view returns(uint){
        return totalTokens;
    }
   
    modifier enoughTokens(address _from, uint _amount) {   // проверка того что на балансе для списания есть $$
        require(balanceOf(_from) >= _amount, "not enough tokens!");
        _;
    }

    modifier onlyOwner() {                              //проверка собственности
        require(msg.sender == owner, "not an owner!");
        _;
    }

    constructor (string memory name_, string memory symbol_, uint initialSupply, address shop) { //имя, символ, сколько токенов изначально введено в оборот, адресс магазина по распространению токенов
        _name = name_;            //
        _symbol = symbol_;
        owner = msg.sender;
    }

    function balanceOf(address account) public view returns(uint){
        return balances[account]; //возвращает баланс аккаунта
    }
    function transfer(address to, uint amount) external enoughTokens(msg.sender, amount) { // перевод с кошелька инициатора транзакции to  на другой кошелек с проверкой есть ли $$
        _beforeTokenTransfer(msg.sender, to, amount); // проверка правильности адресов и колличества
        balances[msg.sender] -= amount; // забрал у себя
        balances[to] += amount;  // добавил получателя
        emit Transfer(msg.sender, to, amount); //инициализация события перевода $$
    }
   
    function mint( uint amount, address shop) public onlyOwner {  // ввод токенов в оборот и зачисление на адресс
        _beforeTokenTransfer(address(0), shop, amount);
        balances[shop] += amount; //на баланс магазина добавить amount токенов
        totalTokens += amount;  //контрлируем добавление токенов к вообщеначисленным токенам
        emit Transfer(address(0), shop, amount);  //порождение события отправки токенов на нулевого адреса в магазин в колличестве amount
    }

    function burn(address _from, uint amount) public onlyOwner enoughTokens(_from, amount) { // "сжигаем" лишние токены
        _beforeTokenTransfer(_from, address(0), amount);
        balances[_from] -= amount;
        totalTokens -= amount;
    }
    function allowance(address _owner, address spender) public view returns(uint){  //проверка может ли сторонний аккаунт списать $$ в свою пользу без моего разрешения
         return allowances[_owner][spender];
    }
    function approve (address spender, uint amount) public {  //кому и сколько я разрешаю забирать токенов
        _approve(msg.sender, spender, amount);
    }
    function _approve(address sender, address spender, amount) internal virtual {
        allowances[sender][spender] = amount;
        emit Approve(sender, spender, amount); //порождение собыия Approve
    }

    function transferFrom(address sender, address recipient, uint amount ) external enoughTokens(sender, amount) { // функция забирает из sender отдает в recipient, проверка если ли у sender $$
        _beforeTokenTransfer(sender, recipient, amount);
        require(allowances[sender][recipient]) >= amount, "check allowance!");  // что у sender больше $$ чем amount, т.к. транзакция слетит если вернется отрицательное значение , потому что переменная uint -беззнаковая
        allowances[sender][recipient] -= amount;
        balances[sender] -= amount;
        balances[recipient] += amount;
        emit Transfer(sender, recipient, amount);
    }
// ниже написана функция выполняющаяся до перевода $$ для наибольше безопасности
    function _beforeTokenTransfer(
        address from,   //адрес откуда
        address to,     //адрес куда
        uint amount     // сколько
    ) internal virtual {}   //virtual используется для переопределения функции ниже по иерархии
}
// создаем новый контракт магазина youName
contract youName is ERC20 {
    constructor(address shop) ERC20 ("ERC20","ERC20", 100500100155, shop) { //обращается к конструктору в родительском контракте и передает ему значения
    }
contract youNameShop {    // контракт магазина токенов
    IERC20 public token;       // описывает взаимодействие с интерфейсом IERC20.sol
    address payable public owner;   // платежеспособный адрес собственника
    event Bought(uint _amount, address indexed _buyer); // событие покупки содержит сколько и адрес покупателя
    event Sold( uint _amount, address indexed _seller); // событие продажи, сколько и адрес продавца

    constructor(){
        token = new youName(address(this)); // new - операция развертывания стороннего смарт-контракта, по адресу нашего магазина (this)
        owner = payable(msg.sender); //делаем адресс owner сразу способным получать/переводить денюшку
    }  
    modifier onlyOwner() {                              //проверка собственности, только владелец может выводить деньги
        require(msg.sender == owner, "not an owner!");
        _;
    }
    function sell (uint _amountToSell) external {  // функция продажи токена
        require(
            _amountToSell > 0 &&   // проверка наличия токенов так как  totalTokens может закончится
            token.balanceOf(msg.sender) >= _amountToSell, "incorrect amount" // проверка наличия у покупателя средств для покупки запрашиваемого количества токенов
        );
        uint allowance = token.allowance(msg.sender, address(this));
        require(allowance >= _amountToSell, "check allowance!");      // проверка того что покупатель разрешил списать $$ с его счёта
        token.transferFrom(msg.sender. address(this), amountToSell); // при прохождении проверки магазан забирает оплату от покупателя
        payable(msg.sender).transfer(_amountToSell) // передача продавцу токенов его $$
        emit Sold(_amountToSell, msg.sender);  // событие продажи в количестве и кем продано
    }
   
    receive() external payable { // fallback - функция, принимающая средства от покупателей, вызывается автоматически если в контракт просто пришли $$ / типа просто перевод без вызова функции покупки/ продажи
        uint tokenToBuy = msg.value; // при покупке 1 token за 1 wai
        require(tokenToBuy > 0, "not enough funds"); // проверка количества покупаемых токенов

        uint currentBalance = tokenBalance(); //чтобы не получилось что токенов к продаже меньше чем токенов хочет покупатель
        require(currentBalance >= tokenToBuy, " not enough tokens!");

        token.transfer(msg.sender, tokenToBuy); // переводим токены тому кто запросил в необходимом колличестве
        emit Bought(tokenToBuy, msg.sender); // породили событие покупки
       
    }
    function tockenBalance() public view returns (uint){ //сколько на счету магазина есть токенов
        return tokenBalanceOf(address(this));  
    }
}

Функции скама в следующих заметках.
А где следующие заметки?:)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх