├── pink-anti-bot-dashboard.png ├── IPinkAntiBot.sol ├── README.md └── ExampleAntiBotERC20.sol /pink-anti-bot-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pinkmoonfinance/pink-antibot-guide/HEAD/pink-anti-bot-dashboard.png -------------------------------------------------------------------------------- /IPinkAntiBot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IPinkAntiBot { 5 | function setTokenOwner(address owner) external; 6 | 7 | function onPreTransferCheck( 8 | address from, 9 | address to, 10 | uint256 amount 11 | ) external; 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PinkAntiBot Contract Address: 2 | 3 | 1. MAINNET: 0xf4f071EB637b64fC78C9eA87DaCE4445D119CA35 4 | 2. BSC: 0x8EFDb3b642eb2a20607ffe0A56CFefF6a95Df002 5 | 3. BSC_TESTNET: 0xbb06F5C7689eA93d9DeACCf4aF8546C4Fe0Bf1E5 6 | 4. MATIC: 0x56a79881b65B03F27b088B753B6c128485642FC3 7 | 5. KCC_MAINNET: 0x2A7F08C820f3382D38B855ba59ad26444938a2b5 8 | 6. AVAX: 0x18F349aD12d7d7f029B3b22e0B01c6D88a0D2066 9 | 7. FTM: 0xcA461AcF6A9E68FA6D53410eba43cefde7dF5466 10 | 8. CRONOS: 0x785A195F7b6a0dDaf7E41EBcBddE7a98F4Cb24A9 11 | 12 | ## PinkAntiBot integration guide 13 | 14 | 1. Add this interface to your codebase: 15 | 16 | `IPinkAntiBot.sol` 17 | ```solidity 18 | // SPDX-License-Identifier: MIT 19 | pragma solidity >=0.5.0; 20 | 21 | interface IPinkAntiBot { 22 | function setTokenOwner(address owner) external; 23 | 24 | function onPreTransferCheck( 25 | address from, 26 | address to, 27 | uint256 amount 28 | ) external; 29 | } 30 | ``` 31 | 32 | 2. Update your token contract: 33 | 34 | ```diff 35 | +import "path/to/IPinkAntiBot.sol"; 36 | 37 | contract MyToken { 38 | + IPinkAntiBot public pinkAntiBot; 39 | 40 | constructor( 41 | string memory name_, 42 | string memory symbol_, 43 | uint8 decimals_, 44 | uint256 totalSupply_, 45 | + address pinkAntiBot_ 46 | ) { 47 | ... omitted for clarity 48 | 49 | // Create an instance of the PinkAntiBot variable from the provided address 50 | + pinkAntiBot = IPinkAntiBot(pinkAntiBot_); 51 | // Register the deployer to be the token owner with PinkAntiBot. You can 52 | // later change the token owner in the PinkAntiBot contract 53 | + pinkAntiBot.setTokenOwner(msg.sender); 54 | } 55 | 56 | // Inside ERC20's _transfer function: 57 | function _transfer( 58 | address sender, 59 | address recipient, 60 | uint256 amount 61 | ) internal virtual { 62 | require(sender != address(0), "ERC20: transfer from the zero address"); 63 | require(recipient != address(0), "ERC20: transfer to the zero address"); 64 | + pinkAntiBot.onPreTransferCheck(sender, recipient, amount); 65 | } 66 | } 67 | ``` 68 | 69 | 3. Visit https://www.pinksale.finance/#/antibot, update your settings. After that please enable Pink Anti-Bot (Pay 1 BNB fee at first time) 70 | 71 | ![alt text](https://github.com/pinkmoonfinance/pink-antibot-guide/blob/main/pink-anti-bot-dashboard.png) 72 | 73 | 4. (Optional): If you want more control over how `PinkAntiBot` is enabled or disabled, you can do it inside your contract instead of relying on `PinkAntiBot` contract's configuration: 74 | 75 | 76 | ```diff 77 | import "path/to/IPinkAntiBot.sol"; 78 | 79 | contract MyToken { 80 | IPinkAntiBot public pinkAntiBot; 81 | + bool public antiBotEnabled; 82 | 83 | constructor( 84 | string memory name_, 85 | string memory symbol_, 86 | uint8 decimals_, 87 | uint256 totalSupply_, 88 | address pinkAntiBot_ 89 | ) { 90 | ... omitted for clarity 91 | 92 | // Create an instance of the PinkAntiBot variable from the provided address 93 | pinkAntiBot = IPinkAntiBot(pinkAntiBot_); 94 | // Register the deployer to be the token owner with PinkAntiBot. You can 95 | // later change the token owner in the PinkAntiBot contract 96 | pinkAntiBot.setTokenOwner(msg.sender); 97 | + antiBotEnabled = true; 98 | } 99 | 100 | // Use this function to control whether to use PinkAntiBot or not instead 101 | // of managing this in the PinkAntiBot contract 102 | + function setEnableAntiBot(bool _enable) external onlyOwner { 103 | + antiBotEnabled = _enable; 104 | + } 105 | 106 | // Inside ERC20's _transfer function: 107 | function _transfer( 108 | address sender, 109 | address recipient, 110 | uint256 amount 111 | ) internal virtual { 112 | require(sender != address(0), "ERC20: transfer from the zero address"); 113 | require(recipient != address(0), "ERC20: transfer to the zero address"); 114 | // Only use PinkAntiBot if this state is true 115 | + if (antiBotEnabled) { 116 | pinkAntiBot.onPreTransferCheck(sender, recipient, amount); 117 | + } 118 | } 119 | } 120 | ``` 121 | -------------------------------------------------------------------------------- /ExampleAntiBotERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.7.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | 9 | interface IPinkAntiBot { 10 | function setTokenOwner(address owner) external; 11 | 12 | function onPreTransferCheck( 13 | address from, 14 | address to, 15 | uint256 amount 16 | ) external; 17 | } 18 | 19 | contract ERC20 is IERC20, Ownable { 20 | using SafeMath for uint256; 21 | 22 | mapping(address => uint256) private _balances; 23 | 24 | mapping(address => mapping(address => uint256)) private _allowances; 25 | 26 | uint256 private _totalSupply; 27 | 28 | string private _name; 29 | string private _symbol; 30 | uint8 private _decimals; 31 | 32 | IPinkAntiBot public pinkAntiBot; 33 | bool public antiBotEnabled; 34 | 35 | constructor( 36 | string memory name_, 37 | string memory symbol_, 38 | uint256 totalSupply_, 39 | address pinkAntiBot_ 40 | ) { 41 | _name = name_; 42 | _symbol = symbol_; 43 | _decimals = 18; 44 | _mint(msg.sender, totalSupply_); 45 | 46 | // Initiate PinkAntiBot instance from its address 47 | pinkAntiBot = IPinkAntiBot(pinkAntiBot_); 48 | // Register deployer as the owner of this token with PinkAntiBot contract 49 | pinkAntiBot.setTokenOwner(msg.sender); 50 | // Enable using PinkAntiBot in this contract 51 | antiBotEnabled = true; 52 | } 53 | 54 | // When you done launching your tokens, simply set this to 55 | // false so your token does not use PinkAntiBot anymore 56 | function setUsingAntiBot(bool enabled_) external onlyOwner { 57 | antiBotEnabled = enabled_; 58 | } 59 | 60 | function name() public view virtual returns (string memory) { 61 | return _name; 62 | } 63 | 64 | function symbol() public view virtual returns (string memory) { 65 | return _symbol; 66 | } 67 | 68 | function decimals() public view virtual returns (uint8) { 69 | return _decimals; 70 | } 71 | 72 | function totalSupply() public view virtual override returns (uint256) { 73 | return _totalSupply; 74 | } 75 | 76 | function balanceOf(address account) public view virtual override returns (uint256) { 77 | return _balances[account]; 78 | } 79 | 80 | function transfer(address recipient, uint256 amount) public virtual override returns (bool) { 81 | _transfer(_msgSender(), recipient, amount); 82 | return true; 83 | } 84 | 85 | function allowance(address owner, address spender) 86 | public 87 | view 88 | virtual 89 | override 90 | returns (uint256) 91 | { 92 | return _allowances[owner][spender]; 93 | } 94 | 95 | function approve(address spender, uint256 amount) public virtual override returns (bool) { 96 | _approve(_msgSender(), spender, amount); 97 | return true; 98 | } 99 | 100 | function transferFrom( 101 | address sender, 102 | address recipient, 103 | uint256 amount 104 | ) public virtual override returns (bool) { 105 | _transfer(sender, recipient, amount); 106 | _approve( 107 | sender, 108 | _msgSender(), 109 | _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance") 110 | ); 111 | return true; 112 | } 113 | 114 | function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { 115 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); 116 | return true; 117 | } 118 | 119 | function decreaseAllowance(address spender, uint256 subtractedValue) 120 | public 121 | virtual 122 | returns (bool) 123 | { 124 | _approve( 125 | _msgSender(), 126 | spender, 127 | _allowances[_msgSender()][spender].sub( 128 | subtractedValue, 129 | "ERC20: decreased allowance below zero" 130 | ) 131 | ); 132 | return true; 133 | } 134 | 135 | function _transfer( 136 | address sender, 137 | address recipient, 138 | uint256 amount 139 | ) internal virtual { 140 | require(sender != address(0), "ERC20: transfer from the zero address"); 141 | require(recipient != address(0), "ERC20: transfer to the zero address"); 142 | 143 | // When you done launching, you can call setUsingAntiBot(false) to 144 | // disable PinkAntiBot in your token instead of interacting with the 145 | // PinkAntiBot contract 146 | if (antiBotEnabled) { 147 | // Check for malicious transfers 148 | pinkAntiBot.onPreTransferCheck(sender, recipient, amount); 149 | } 150 | 151 | // We dont check inside this hook because we dont care about 152 | // minting and burning transfers 153 | _beforeTokenTransfer(sender, recipient, amount); 154 | 155 | _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); 156 | _balances[recipient] = _balances[recipient].add(amount); 157 | emit Transfer(sender, recipient, amount); 158 | } 159 | 160 | function _mint(address account, uint256 amount) internal virtual { 161 | require(account != address(0), "ERC20: mint to the zero address"); 162 | 163 | _beforeTokenTransfer(address(0), account, amount); 164 | 165 | _totalSupply = _totalSupply.add(amount); 166 | _balances[account] = _balances[account].add(amount); 167 | emit Transfer(address(0), account, amount); 168 | } 169 | 170 | function _burn(address account, uint256 amount) internal virtual { 171 | require(account != address(0), "ERC20: burn from the zero address"); 172 | 173 | _beforeTokenTransfer(account, address(0), amount); 174 | 175 | _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); 176 | _totalSupply = _totalSupply.sub(amount); 177 | emit Transfer(account, address(0), amount); 178 | } 179 | 180 | function _approve( 181 | address owner, 182 | address spender, 183 | uint256 amount 184 | ) internal virtual { 185 | require(owner != address(0), "ERC20: approve from the zero address"); 186 | require(spender != address(0), "ERC20: approve to the zero address"); 187 | 188 | _allowances[owner][spender] = amount; 189 | emit Approval(owner, spender, amount); 190 | } 191 | 192 | function _setupDecimals(uint8 decimals_) internal virtual { 193 | _decimals = decimals_; 194 | } 195 | 196 | function _beforeTokenTransfer( 197 | address from, 198 | address to, 199 | uint256 amount 200 | ) internal virtual {} 201 | } 202 | --------------------------------------------------------------------------------