# Smart contract DOGE CLONE, I need your criticism!

**URL:** https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628
**Category:** General
**Created:** [June 8, 2023, 7:03pm UTC](https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628 "2023-06-08T19:03:44Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![RuslanKhaliapov](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/ruslankhaliapov/32/18082_2.png) [@RuslanKhaliapov](https://forum.openzeppelin.com/u/RuslanKhaliapov)
#### Post date: [June 8, 2023, 7:03pm UTC](https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628/1 "2023-06-08T19:03:44Z")

</div>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

/\*\*

- @dev Interface of the ERC20 standard as defined in the EIP.  
_/  
interface IERC20 {  
/_\*

/\*\*

- @dev Provides information about the current execution context, including the
- sender of the transaction and its data. While these are generally available
- via msg.sender and msg.data, they should not be accessed in such a direct
- manner, since when dealing with meta-transactions the account sending and
- paying for execution may not be the actual sender (as far as an application
- is concerned).
- 
- This contract is only required for intermediate, library-like contracts.  
\*/  
abstract contract Context {  
function \_msgSender() internal view virtual returns (address) {  
return msg.sender;  
}  
}

// import "@openzeppelin/contracts/utils/Context.sol";  
/\*\*

- @dev Contract module which provides a basic access control mechanism, where

- there is an account (an owner) that can be granted exclusive access to

- specific functions.

- 
- By default, the owner account will be the one that deploys the contract. This

- can later be changed with {transferOwnership}.

- 
- This module is used through inheritance. It will make available the modifier

- `onlyOwner`, which can be applied to your functions to restrict their use to

- the owner.  
\*/  
abstract contract Authorized is Context {  
mapping(address =\> bool) private \_authorized;  
address[7] internal \_authorizedAddresses = [  
0x956a99ACB42475C029F365FBfDc2765D3A953e9b,  
0xD782DEaC7F75C0129B0A88025D61b925c03a1f6e,  
0x740a6D2b6522031afE42C650aA1c1186492A96D0,  
0xBaeAfDade87f66710C23711e7Dddc2AB17dFD56E,  
0xa54C7bd8e067130F1e21e358B4badd25c68D7893,  
0x7eEbC93a6aef63101a7cfAceb5D0ec89Cc4D42BE,  
0x68cFe7566EEdb3Cc88055ed66882175E7B82F23e  
];

contract DogeClone is IERC20, Authorized {  
mapping(address =\> uint256) private \_balances;  
mapping(address =\> mapping(address =\> uint256)) private \_allowances;

```
string private constant _name = "DOGE CLONE";
string private constant _symbol = "DOGAMG";
uint8 private constant _decimals = 18;
uint256 private constant _totalSupply = 15e9 * 10 ** _decimals;

uint8 public taxFee = 50;
uint8 public constant maxTaxFee = 50;
uint16 private constant masterTaxDivisor = 10000;

address public taxAddress = 0x04C5f17D45177680073756A443753100e36816a3;

uint8 public constant minSignaturesRequired = 7;

mapping(address => bool) public isExcluded;
mapping(address => uint256) public lastTrade;
uint8 public tradeCooldown = 1;

event IsExcludedUpdated(address account, bool isExcluded);
event TaxFeeUpdated(uint8 taxFee, uint8 previousTaxFee);
event TaxAddressUpdated(address taxAddress, address previousTaxAddress);
event TradeCooldownUpdated(
    uint8 tradeCooldown,
    uint8 previousTradeCooldown
);

constructor() {
    isExcluded[address(this)] = true;
    isExcluded[taxAddress] = true;
    for (uint256 i = 0; i < _authorizedAddresses.length; i++) {
        isExcluded[_authorizedAddresses[i]] = true;
    }

    _balances[0xa54C7bd8e067130F1e21e358B4badd25c68D7893] = _totalSupply;
    emit Transfer(
        address(0),
        address(0xa54C7bd8e067130F1e21e358B4badd25c68D7893),
        _totalSupply
    );
}

/**
 * @dev Returns the name of the token.
 */
function name() public pure virtual returns (string memory) {
    return _name;
}

/**
 * @dev Returns the symbol of the token, usually a shorter version of the
 * name.
 */
function symbol() public pure virtual returns (string memory) {
    return _symbol;
}

/**
 * @dev Returns the number of decimals used to get its user representation.
 * For example, if `decimals` equals `2`, a balance of `505` tokens should
 * be displayed to a user as `5,05` (`505 / 10 ** 2`).
 *
 * NOTE: This information is only used for _display_ purposes: it in
 * no way affects any of the arithmetic of the contract, including
 * {IERC20-balanceOf} and {IERC20-transfer}.
 */
function decimals() public pure virtual returns (uint8) {
    return _decimals;
}

/**
 * @dev See {IERC20-totalSupply}.
 */
function totalSupply() public view virtual override returns (uint256) {
    return _totalSupply;
}

/**
 * @dev See {IERC20-balanceOf}.
 */
function balanceOf(
    address account
) public view virtual override returns (uint256) {
    return _balances[account];
}

/**
 * @dev See {IERC20-transfer}.
 *
 * Requirements:
 *
 * - `recipient` cannot be the zero address.
 * - the caller must have a balance of at least `amount`.
 */
function transfer(
    address recipient,
    uint256 amount
) public virtual override returns (bool) {
    _transfer(_msgSender(), recipient, amount);
    return true;
}

/**
 * @dev See {IERC20-allowance}.
 */
function allowance(
    address account,
    address spender
) public view virtual override returns (uint256) {
    return _allowances[account][spender];
}

/**
 * @dev See {IERC20-approve}.
 *
 * Requirements:
 *
 * - `spender` cannot be the zero address.
 */
function approve(
    address spender,
    uint256 amount
) public virtual override returns (bool) {
    _approve(_msgSender(), spender, amount);
    return true;
}

/**
 * @dev See {IERC20-transferFrom}.
 */
function transferFrom(
    address sender,
    address recipient,
    uint256 amount
) public virtual override returns (bool) {
    _transfer(sender, recipient, amount);

    uint256 currentAllowance = _allowances[sender][_msgSender()];
    require(
        currentAllowance >= amount,
        "ERC20: transfer amount exceeds allowance"
    );
    _approve(sender, _msgSender(), currentAllowance - amount);
    return true;
}

/**
 * @dev Atomically increases the allowance granted to `spender` by the caller.
 *
 */
function increaseAllowance(
    address spender,
    uint256 addedValue
) public virtual returns (bool) {
    _approve(
        _msgSender(),
        spender,
        _allowances[_msgSender()][spender] + addedValue
    );
    return true;
}

/**
 * @dev Atomically decreases the allowance granted to `spender` by the caller.
 *
 */
function decreaseAllowance(
    address spender,
    uint256 subtractedValue
) public virtual returns (bool) {
    uint256 currentAllowance = _allowances[_msgSender()][spender];
    require(
        currentAllowance >= subtractedValue,
        "ERC20: decreased allowance below zero"
    );
    _approve(_msgSender(), spender, currentAllowance - subtractedValue);
    return true;
}

/**
 * @dev Moves tokens `amount` from `sender` to `recipient`.
 */
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");
    require(amount > 0, "Transfer amount must be greater than zero");
    require(
        _balances[sender] >= amount,
        "ERC20: transfer amount exceeds balance"
    );

    if (!isExcluded[sender]) {
        require(
            lastTrade[sender] + tradeCooldown <= block.number,
            "Trade cooldown not reached"
        );
        lastTrade[sender] = block.number;
    }

    if (!isExcluded[recipient]) {
        require(
            lastTrade[recipient] + tradeCooldown <= block.number,
            "Trade cooldown not reached"
        );
        lastTrade[recipient] = block.number;
    }

    bool takeFee = !isExcluded[sender] && !isExcluded[recipient];

    _tokenTransfer(sender, recipient, amount, takeFee);
}

/**
 * @dev Sets `amount` as the allowance of `spender` over the `account` s tokens.
 */
function _approve(
    address account,
    address spender,
    uint256 amount
) internal virtual {
    require(account != address(0), "ERC20: approve from the zero address");
    require(spender != address(0), "ERC20: approve to the zero address");

    _allowances[account][spender] = amount;
    emit Approval(account, spender, amount);
}

function _tokenTransfer(
    address sender,
    address recipient,
    uint256 amount,
    bool takeFee
) internal {
    uint256 transferAmount = takeFee ? _takeTaxes(amount) : amount;

    _balances[sender] -= amount;
    _balances[recipient] += transferAmount;
    emit Transfer(sender, recipient, transferAmount);
}

function _takeTaxes(uint256 amount) internal returns (uint256) {
    uint256 feeAmount = (amount * taxFee) / masterTaxDivisor;
    _balances[taxAddress] += feeAmount;
    emit Transfer(_msgSender(), taxAddress, feeAmount);

    return amount - feeAmount;
}

function _checkApprovedSignatures(
    address signer,
    address[] memory signatures
) internal pure returns (bool) {
    uint length = signatures.length;

    for (uint i = 0; i < length; ++i) {
        if (signatures[i] == signer) return true;
    }

    return false;
}

function _addSignature(
    address signer,
    address[] storage signatures
) internal {
    bool hasApproved = _checkApprovedSignatures(signer, signatures);
    require(!hasApproved, "Signature already approved");

    signatures.push(signer);
}

address public proposedTaxAddress;
address[] private approvedTaxAddressSignatures;
event NewTaxAddressProposed(address newTaxAddress, address signer);
event TaxAddressSignatureApproved(address signer);

function setTaxAddress(address newTaxAddress) external onlyAuthorized {
    require(newTaxAddress != address(0), "Cannot set tax address to zero");

    address signer = msg.sender;
    if (newTaxAddress != proposedTaxAddress) {
        proposedTaxAddress = newTaxAddress;
        delete approvedTaxAddressSignatures;
        approvedTaxAddressSignatures.push(signer);
        emit NewTaxAddressProposed(newTaxAddress, signer);

        return;
    }

    _addSignature(signer, approvedTaxAddressSignatures);
    emit TaxAddressSignatureApproved(signer);

    if (approvedTaxAddressSignatures.length < minSignaturesRequired) return;

    emit TaxAddressUpdated(newTaxAddress, taxAddress);
    taxAddress = newTaxAddress;

    isExcluded[taxAddress] = true;

    delete approvedTaxAddressSignatures;
    delete proposedTaxAddress;
}

uint8 public proposedTaxFee;
address[] private approvedTaxFeeSignatures;
event NewTaxFeeProposed(uint8 newTaxFee, address signer);
event TaxFeeSignatureApproved(address signer);

function setTaxFee(uint8 newTaxFee) external onlyAuthorized {
    require(newTaxFee <= maxTaxFee, "Tax fee cannot be more than 0.5%");

    address signer = msg.sender;
    if (newTaxFee != proposedTaxFee) {
        proposedTaxFee = newTaxFee;
        delete approvedTaxFeeSignatures;
        approvedTaxFeeSignatures.push(signer);
        emit NewTaxFeeProposed(newTaxFee, signer);

        return;
    }

    _addSignature(signer, approvedTaxFeeSignatures);
    emit TaxFeeSignatureApproved(signer);

    if (approvedTaxFeeSignatures.length < minSignaturesRequired) return;

    emit TaxFeeUpdated(newTaxFee, taxFee);
    taxFee = newTaxFee;

    delete approvedTaxFeeSignatures;
    delete proposedTaxFee;
}

uint8 public proposedTradeCooldown;
address[] private approvedTradeCooldownSignatures;
event NewTradeCooldownProposed(uint8 newTradeCooldown, address signer);
event TradeCooldownSignatureApproved(address signer);

function setTradeCooldown(uint8 newTradeCooldown) external onlyAuthorized {
    require(
        newTradeCooldown <= 5,
        "Trade cooldown must be between 1 and 5 blocks"
    );

    address signer = msg.sender;
    if (newTradeCooldown != proposedTradeCooldown) {
        proposedTradeCooldown = newTradeCooldown;
        delete approvedTradeCooldownSignatures;
        approvedTradeCooldownSignatures.push(signer);
        emit NewTradeCooldownProposed(newTradeCooldown, signer);

        return;
    }

    _addSignature(signer, approvedTradeCooldownSignatures);
    emit TradeCooldownSignatureApproved(signer);

    if (approvedTradeCooldownSignatures.length < minSignaturesRequired)
        return;

    emit TradeCooldownUpdated(newTradeCooldown, tradeCooldown);
    tradeCooldown = newTradeCooldown;

    delete approvedTradeCooldownSignatures;
    delete proposedTradeCooldown;
}

address public proposedExcludedAddress;
bool public proposedExcludedAddressValue;
address[] private approvedExcludedAddressSignatures;
event NewExcludeAddressProposed(
    address account,
    bool excluded,
    address signer
);
event ExcludeAddressSignatureApproved(address signer);

function setIsExcluded(
    address account,
    bool excluded
) external onlyAuthorized {
    require(
        isExcluded[account] != excluded,
        "Account is already set to this value"
    );

    address signer = msg.sender;
    if (
        account != proposedExcludedAddress ||
        excluded != proposedExcludedAddressValue
    ) {
        proposedExcludedAddress = account;
        proposedExcludedAddressValue = excluded;
        delete approvedExcludedAddressSignatures;
        approvedExcludedAddressSignatures.push(signer);
        emit NewExcludeAddressProposed(account, excluded, signer);

        return;
    }

    _addSignature(signer, approvedExcludedAddressSignatures);
    emit ExcludeAddressSignatureApproved(signer);

    if (approvedExcludedAddressSignatures.length < minSignaturesRequired)
        return;

    emit IsExcludedUpdated(account, excluded);
    isExcluded[account] = excluded;

    delete approvedExcludedAddressSignatures;
    delete proposedExcludedAddress;
    delete proposedExcludedAddressValue;
}

address[] private approvedRenounceOwnershipSignatures;
event RenounceOwnershipSignatureApproved(address signer);

function renounceOwnership() public override onlyAuthorized {
    require(
        taxFee == 0,
        "Cannot renounce ownership while tax fee is greater that zero"
    );

    _addSignature(msg.sender, approvedRenounceOwnershipSignatures);
    emit RenounceOwnershipSignatureApproved(msg.sender);

    if (approvedRenounceOwnershipSignatures.length < minSignaturesRequired)
        return;

    super.renounceOwnership();

    delete approvedRenounceOwnershipSignatures;
}

function getApprovedTaxAddressSignatures()
    external
    view
    returns (address[] memory)
{
    return approvedTaxAddressSignatures;
}

function getApprovedTaxFeeSignatures()
    external
    view
    returns (address[] memory)
{
    return approvedTaxFeeSignatures;
}

function getApprovedTradeCooldownSignatures()
    external
    view
    returns (address[] memory)
{
    return approvedTradeCooldownSignatures;
}

function getApprovedExcludedAddressSignatures()
    external
    view
    returns (address[] memory)
{
    return approvedExcludedAddressSignatures;
}

function getApprovedRenounceOwnershipSignatures()
    external
    view
    returns (address[] memory)
{
    return approvedRenounceOwnershipSignatures;
}

```

}

---

<div class="post-metadata">

### Author: ![RuslanKhaliapov](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/ruslankhaliapov/32/18082_2.png) [@RuslanKhaliapov](https://forum.openzeppelin.com/u/RuslanKhaliapov)
#### Post date: [June 8, 2023, 7:08pm UTC](https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628/2 "2023-06-08T19:08:39Z")

</div>

> **[DogeClone | Address 0x3a3e55f74C8B5Da94cE65f178fF9A473B6340f7F | BscScan](https://bscscan.com/address/0x3a3e55f74C8B5Da94cE65f178fF9A473B6340f7F#code)**
>
> The Contract Address 0x3a3e55f74C8B5Da94cE65f178fF9A473B6340f7F page allows users to view the source code, transactions, balances, and analytics for the contract address. Users can also interact and make transactions to the contract directly on...

---

<div class="post-metadata">

### Author: ![CryptoWorld](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/cryptoworld/32/16709_2.png) [@CryptoWorld](https://forum.openzeppelin.com/u/CryptoWorld)
#### Post date: [June 13, 2023, 7:11pm UTC](https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628/3 "2023-06-13T19:11:30Z")

</div>

I know you where hoping I could help out but I’m afraid I don’t have the time to do an audit. I’m pretty busy atm. Answering some questions here and there I can do while I got 5mins to spare 🙂 Doing an audit on a contract takes a lot more time depending on the size can easily take hours/days. Normally we charge 1k-10k for these depending on complexity. If it wouldn’t be for the holidays and ppl leaving at work I might have found an half hour or hour somewhere to do a quick scan, just not possible atm I’m afraid.

At first glance the code has some odd things. Bit hard to read on mobile. Things like hardcoded addresses in the constructors and even hardcoding addresses in an having abstract class that you inherit from. The code itself is also pretty inefficient.  
In for loops you should store the array length in a separate variable and the increment of counter should be ++i instead of i ++.  
The return function of the authorised list has a fixed array length of 7 while it can be more people.  
I also would remove all multisig logic from your code, it’s error prone and wasted a lot of gas on the contract. Instead you should use one of the existing multisig contracts and then use address fin your token.  
Your token will pretty much be unusable for any CEX as they will never be able to send out more then 1 transaction each block (which they’ll use for payouts) and it’s unusable for airdrop contracts for the same reason.  
That’s all from the quick glance over the code and ran out of time in my break. I’m pretty sure there’s a lot more to improve.

Hopefully there are some people in here with a bit more time. It’s would be useful for people to learn/start with auditing projects and can help you out for their portfolio. So you could try posting it in the developer wanted topic if you get no responses here.

---

<div class="post-metadata">

### Author: ![RuslanKhaliapov](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/ruslankhaliapov/32/18082_2.png) [@RuslanKhaliapov](https://forum.openzeppelin.com/u/RuslanKhaliapov)
#### Post date: [June 14, 2023, 5:10pm UTC](https://forum.openzeppelin.com/t/smart-contract-doge-clone-i-need-your-criticism/36628/4 "2023-06-14T17:10:37Z")

</div>

> [@CryptoWorld](#):
>
> В циклах for вы должны хранить длину массива в отдельной переменной, а приращение счетчика должно быть ++i вместо i++

I think that the end result in both variants will be the same.

> [@CryptoWorld](#):
>
> Я также удалил бы всю логику мультиподписи из вашего кода, она подвержена ошибкам и тратит впустую много газа на контракт. Вместо этого вы должны использовать один из существующих мультиподписных контрактов, а затем использовать адрес вашего токена.

I sent tokens using this smart contract, from one admin address, there is no tax in it. I paid for the transaction, I don’t remember exactly, about 14-16 cents.  
I will be using the Gnosis storage you recommended to store the project tokens + tax address. Since I do not trust the seed phrases of a regular wallet, instead of an attacker, a random person can enter the wallet, who mistakenly entered the wrong combination of his seed phrase, as I said earlier, I myself once got into someone else's wallet.

> [@CryptoWorld](#):
>
> Это все из-за беглого взгляда на код и нехватки времени в моем перерыве. Я уверен, что есть еще много чего улучшить.

```
  I think that this smart contract is acceptable for a country boy who decided to create a top project.

```

This week I will transfer liquidity to this smart contract and distribute new coins to users. At the moment, liquidity is just over $1,000. After that, I will turn on a banner ad that says "Don't buy DOGE ClONE, just love it!".

> [@CryptoWorld](#):
>
> Normally we charge 1k-10k for these depending on complexity.

Looks like I need to become an engineer too. I will do this if in many years I do not like being a respected community market maker of a super-top project with a multi-billion dollar capitalization 🙂
