# Upgrade Token to include partial burn on transfer

**URL:** <https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423>\
**Category:** SDK\
**Created:** [September 26, 2019, 4:09am UTC](https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423 "2019-09-26T04:09:41Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![costech](https://avatars.discourse-cdn.com/v4/letter/c/9de0a6/32.png) [@costech](https://forum.openzeppelin.com/u/costech)\
**Post date:** [September 26, 2019, 4:09am UTC](https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423/1 "2019-09-26T04:09:41Z")

</div>

@abcoathup, how can I upgrade from a SimpleToken contract without partial burn to support the features as above. say the original contract is…

## MyToken.sol

```auto
    pragma solidity ^0.5.0;

    import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol";
    import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol";

    /**
     * @title MyToken
     * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
     * Note they can later distribute these tokens as they wish using `transfer` and other
     * `ERC20` functions.
     */
    contract MyToken is Initializable, ERC20, ERC20Detailed {
        /**
         * @dev Constructor that gives msg.sender all of existing tokens.
         */
        function initialize(address sender) public initializer {
            ERC20Detailed.initialize("MyToken", "MYT", 18);

            _mint(sender, 10000 * (10 ** uint256(decimals())));
        }
    }
```

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [September 26, 2019, 6:04am UTC](https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423/2 "2019-09-26T06:04:36Z")

</div>

Hi @costech,

To add new functionality in an upgrade,

- add any new state variables (we cannot change types or order of existing state variables)
- add new functions (or modify existing functions)
- setup new state variables in an upgrade function, being sure to appropriately protect the function so that it can only be called once, just as the `initialize` function is protected with the `initializer` modifier.

See the documentation for more information on this:  
[https://docs.openzeppelin.com/sdk/2.5/writing-contracts#modifying-your-contracts](https://docs.openzeppelin.com/sdk/2.5/writing-contracts#modifying-your-contracts)

Please note I have not done any of the required testing.

I recommend that any such contract be fully **tested** and **audited**.  
For testing, I suggest using the following guide: [Test smart contracts like a rockstar](https://forum.openzeppelin.com/t/test-smart-contracts-like-a-rockstar/1001)

It is also recommended to [test your upgrade locally](https://blog.zeppelinos.org/testing-real-world-contract-upgrades/) before running the upgrade in production.

## MyToken.sol V0

Save V0 of MyToken.sol

```auto
pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol";

/**
 * @title MyToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract MyToken is Initializable, ERC20, ERC20Detailed {
    /**
     * @dev Constructor that gives msg.sender all of existing tokens.
     */
    function initialize(address sender) public initializer {
        ERC20Detailed.initialize("MyToken", "MYT", 18);

        _mint(sender, 10000 * (10 ** uint256(decimals())));
    }
}

```

## Create

```auto
$ oz create
✓ Compiled contracts with solc 0.5.11 (commit.c082d0b4)
? Pick a contract to instantiate MyToken
? Pick a network development
✓ Contract MyToken deployed
All contracts have been deployed
? Do you want to call a function on the instance after creating it? Yes
? Select which function * initialize(sender: address)
? sender (address): 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Setting everything up to create contract instances
✓ Instance created at 0x59d3631c86BbE35EF041872d502F218A39FBa150
0x59d3631c86BbE35EF041872d502F218A39FBa150

```

## MyToken.sol V1

Save V1 of MyToken.sol  
Added Mintable and Pausable  
Upgrade is protected by `_upgradeV1` boolean

```auto
pragma solidity ^0.5.0;

import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Mintable.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Pausable.sol";
/**
 * @title MyToken
 * @dev ERC20 Token example, where all tokens are pre-assigned to the creator.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract MyToken is Initializable, ERC20, ERC20Detailed, ERC20Mintable, ERC20Pausable {

    bool private _upgradeV1;
    uint256 private _minimumSupply;

    function initialize(address sender) public initializer {
        ERC20Detailed.initialize("MyToken", "MYT", 18);

        _mint(sender, 10000 * (10 ** uint256(decimals())));
    }

    /**
     * @dev Gives holder all of existing tokens.
     */
    function upgradeV1(address minter, address pauser) public {
        require (!_upgradeV1, "MyToken: already upgraded to V1");
        _upgradeV1 = true;
        
        _addMinter(minter);
        _addPauser(pauser);

        _minimumSupply = 2000 * (10 ** 18);
    }

    function transfer(address to, uint256 amount) public returns (bool) {
        return super.transfer(to, _partialBurn(amount));
    }

    function transferFrom(address from, address to, uint256 amount) public returns (bool) {
        return super.transferFrom(from, to, _partialBurn(amount));
    }

    function _partialBurn(uint256 amount) internal returns (uint256) {
        uint256 burnAmount = _calculateBurnAmount(amount);

        if (burnAmount > 0) {
            _burn(msg.sender, burnAmount);
        }

        return amount.sub(burnAmount);
    }

    function _calculateBurnAmount(uint256 amount) internal view returns (uint256) {
        uint256 burnAmount = 0;

        // burn amount calculations
        if (totalSupply() > _minimumSupply) {
            burnAmount = amount.mul(3).div(100);
            uint256 availableBurn = totalSupply().sub(_minimumSupply);
            if (burnAmount > availableBurn) {
                burnAmount = availableBurn;
            }
        }

        return burnAmount;
    }
}

```

## Upgrade

```auto
$ oz upgrade
? Pick a network development
✓ Compiled contracts with solc 0.5.11 (commit.c082d0b4)
- Variables _minters (MinterRole), _pausers (PauserRole) contain a struct or enum. These are not automatically checked for storage compatibility in the current version. See https://docs.openzeppelin.com/sdk/2.5/writing_contracts.html#modifying-your-contracts for more info.
- New variable 'Roles.Role _minters' was added in contract MinterRole in @openzeppelin/contracts-ethereum-package/contracts/access/roles/MinterRole.sol:1 at the end of the contract.
- New variable 'uint256[50] ______ gap' was added in contract MinterRole in @openzeppelin/contracts-ethereum-package/contracts/access/roles/MinterRole.sol:1 at the end of the contract.
- New variable 'uint256[50] ______ gap' was added in contract ERC20Mintable in @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Mintable.sol:1 at the end of the contract.
- New variable 'Roles.Role _pausers' was added in contract PauserRole in @openzeppelin/contracts-ethereum-package/contracts/access/roles/PauserRole.sol:1 at the end of the contract.
- New variable 'uint256[50] ______ gap' was added in contract PauserRole in @openzeppelin/contracts-ethereum-package/contracts/access/roles/PauserRole.sol:1 at the end of the contract.
- New variable 'bool _paused' was added in contract Pausable in @openzeppelin/contracts-ethereum-package/contracts/lifecycle/Pausable.sol:1 at the end of the contract.
- New variable 'uint256[50] ______ gap' was added in contract Pausable in @openzeppelin/contracts-ethereum-package/contracts/lifecycle/Pausable.sol:1 at the end of the contract.
- New variable 'uint256[50] ______ gap' was added in contract ERC20Pausable in @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Pausable.sol:1 at the end of the contract.
- New variable 'bool _upgradeV1' was added in contract MyToken in contracts/MyToken.sol:1 at the end of the contract.
- New variable 'uint256 _minimumSupply' was added in contract MyToken in contracts/MyToken.sol:1 at the end of the contract.
See https://docs.openzeppelin.com/sdk/2.5/writing_contracts.html#modifying-your-contracts for more info.
✓ Contract MyToken deployed
All contracts have been deployed
? Which instances would you like to upgrade? Choose by address
? Pick an instance to upgrade MyToken at 0x59d3631c86BbE35EF041872d502F218A39FBa150
? Do you want to call a function on the instance after upgrading it? Yes
? Select which function upgradeV1(minter: address, pauser: address)
? minter (address): 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
? pauser (address): 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Instance upgraded at 0x59d3631c86BbE35EF041872d502F218A39FBa150. Transaction receipt: 0x363f0e43abf490f99172ee5344aa5656d018dc8f565bf4a733f88c792c15bb66
✓ Instance at 0x59d3631c86BbE35EF041872d502F218A39FBa150 upgraded

```

## Check new functionality

```auto
$ oz send-tx
? Pick a network development
? Pick an instance MyToken at 0x59d3631c86BbE35EF041872d502F218A39FBa150
? Select which function transfer(to: address, amount: uint256)
? to (address): 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
? amount (uint256): 100
✓ Transaction successful. Transaction hash: 0xbb3c056b3ca931a3b957615c10fec873ff94f75ed3c1cd5344247fabc2222e09

```

```auto
$ oz call
? Pick a network development
? Pick an instance MyToken at 0x59d3631c86BbE35EF041872d502F218A39FBa150
? Select which function balanceOf(owner: address)
? owner (address): 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0
✓ Method 'balanceOf(address)' returned: 97
97

```

---

<div class="post-metadata">

**Author:** ![costech](https://avatars.discourse-cdn.com/v4/letter/c/9de0a6/32.png) [@costech](https://forum.openzeppelin.com/u/costech)\
**Post date:** [September 26, 2019, 7:00am UTC](https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423/3 "2019-09-26T07:00:41Z")

</div>

Thank you. this is very helpful ❤❤

---

<div class="post-metadata">

**Author:** ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)\
**Post date:** [September 26, 2019, 7:33am UTC](https://forum.openzeppelin.com/t/upgrade-token-to-include-partial-burn-on-transfer/1423/4 "2019-09-26T07:33:52Z")

</div>

Hi @costech,

You are most welcome.

Feel free to ask all the questions that you need.
