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