Skip to content

Commit

Permalink
Add burn and burnFrom (#2)
Browse files Browse the repository at this point in the history
* burn, burnFrom

Co-authored-by: Brandon Iles <[email protected]>
  • Loading branch information
brandoniles and Brandon Iles authored Mar 30, 2021
1 parent b995bae commit 62c4467
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
43 changes: 43 additions & 0 deletions contracts/Forth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,49 @@ contract Forth {
_moveDelegates(address(0), delegates[dst], amount);
}

/**
* @notice Destroys `amount` tokens from the caller
* @param rawAmount The number of tokens to burn
*/
function burn(uint256 rawAmount) external {
uint96 amount = safe96(rawAmount, "Forth::burn: rawAmount exceeds 96 bits");
_burn(msg.sender, amount);
}

/**
* @notice Destroys `amount` tokens from `account`, deducting from the caller's allowance
* @param account The address of the account to burn from
* @param rawAmount The number of tokens to burn
*/
function burnFrom(address account, uint256 rawAmount) external {
uint96 amount = safe96(rawAmount, "Forth::burnFrom: rawAmount exceeds 96 bits");

uint96 decreasedAllowance =
sub96(allowances[account][msg.sender], amount, "Forth::burnFrom: amount exceeds allowance");
allowances[account][msg.sender] = decreasedAllowance;
emit Approval(account, msg.sender, decreasedAllowance);

_burn(account, amount);
}

/**
* @notice Destroys `amount` tokens from `account`, reducing the total supply
* @param account The address of the account to burn from
* @param amount The number of tokens to burn
*/
function _burn(address account, uint96 amount) internal {
require(account != address(0), "Forth::_burn: burn from the zero address");

uint96 supply = safe96(totalSupply, "Forth::_burn: old supply exceeds 96 bits");
totalSupply = sub96(supply, amount, "Forth::_burn: amount exceeds totalSupply");

balances[account] = sub96(balances[account], amount, "Forth::_burn: amount exceeds balance");
emit Transfer(account, address(0), amount);

// move delegates
_moveDelegates(delegates[account], address(0), amount);
}

/**
* @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
* @param account The address of the account holding the funds
Expand Down
72 changes: 72 additions & 0 deletions test/Forth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,76 @@ describe('Forth', () => {
'Forth::mint: exceeded mint cap'
)
})

it('burn', async () => {
const { timestamp: now } = await provider.getBlock('latest')
const forth = await deployContract(wallet, Forth, [wallet.address, wallet.address, now + 60 * 60])
const supply = await forth.totalSupply()

// burn 0
let balanceBefore = await forth.balanceOf(wallet.address)
await forth.connect(wallet).burn(0)
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore)
expect(await forth.totalSupply()).to.be.eq(supply)

// burn non-zero
await forth.connect(wallet).burn(1)
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore.sub(1))
expect(await forth.totalSupply()).to.be.eq(supply.sub(1))

// burn > totalSupply
await expect(forth.connect(wallet).burn(supply + 2)).to.be.revertedWith('Forth::_burn: amount exceeds totalSupply')

// burn > balance
await forth.connect(wallet).transfer(other0.address, 100)
balanceBefore = await forth.balanceOf(wallet.address)
await expect(forth.connect(wallet).burn(balanceBefore.add(1))).to.be.revertedWith(
'Forth::_burn: amount exceeds balance'
)
})

it('burnFrom', async () => {
const { timestamp: now } = await provider.getBlock('latest')
const forth = await deployContract(wallet, Forth, [wallet.address, wallet.address, now + 60 * 60])
const supply = await forth.totalSupply()

// burn 0
let balanceBefore = await forth.balanceOf(wallet.address)
await forth.connect(other0).burnFrom(wallet.address, 0)
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore)
expect(await forth.totalSupply()).to.be.eq(supply)

// burn non-zero
await forth.connect(wallet).approve(other0.address, 100)
await forth.connect(other0).burnFrom(wallet.address, 1)
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore.sub(1))
expect(await forth.totalSupply()).to.be.eq(supply.sub(1))

// burn > approval
balanceBefore = await forth.balanceOf(wallet.address)
await forth.connect(wallet).approve(other0.address, 100)
await expect(forth.connect(other0).burnFrom(wallet.address, 101)).to.be.revertedWith(
'Forth::burnFrom: amount exceeds allowance'
)

// burn > totalSupply
balanceBefore = await forth.balanceOf(wallet.address)
await forth.connect(wallet).approve(other0.address, balanceBefore.add(1))
await expect(forth.connect(other0).burnFrom(wallet.address, balanceBefore.add(1))).to.be.revertedWith(
'Forth::_burn: amount exceeds totalSupply'
)

// burn > balance
await forth.connect(wallet).transfer(other0.address, 100)
balanceBefore = await forth.balanceOf(wallet.address)
await forth.connect(wallet).approve(other0.address, balanceBefore.add(1))
await expect(forth.connect(other0).burnFrom(wallet.address, balanceBefore.add(1))).to.be.revertedWith(
'Forth::_burn: amount exceeds balance'
)

// Zero Address
await expect(forth.connect(wallet).burnFrom('0x0000000000000000000000000000000000000000', 0)).to.be.revertedWith(
'Forth::_burn: burn from the zero address'
)
})
})

0 comments on commit 62c4467

Please sign in to comment.